2014-02-20 2 views
4

Мне нужно постоянно выполнять 20 повторяющихся вычислений с интенсивным использованием процессора как можно быстрее. Таким образом, существует 20 задач, которые содержат закодированные методы:Управлять много повторяющимися задачами с интенсивным процессором, выполняемыми параллельно?

while(!token.IsCancellationRequested) 

, чтобы повторить их как можно быстрее. Все вычисления выполняются одновременно. К сожалению, это делает программа не отвечает, так добавил:

await Task.Delay(15); 

На данный момент программа не зависает, но добавление задержки не правильный подход, и это излишне замедляет скорость вычислений. Это программа WPF без MVVM. Какой подход вы предложили бы сохранить одновременно все 20 задач? Каждый из них будет постоянно повторяться, как только он закончится. Я хотел бы сохранить загрузку процессора (всех ядер) с максимальными значениями (или рядом), чтобы обеспечить максимальную эффективность.

EDIT: Существует 20 элементов управления, в которых пользователь настраивает некоторые параметры. Расчеты осуществляются в:

private async Task Calculate() 
{ 
    Task task001 = null; 
    task001 = Task.Run(async() => 
    { 
     while (!CTSFor_task001.IsCancellationRequested) 
     { 
      await Task.Delay(15); 
      await CPUIntensiveMethod(); 
     } 
    }, CTSFor_task001.Token); 
} 

Каждый элемент управления является независимым. Вычисления на 100% связаны с ЦП, без операций ввода-вывода. (Все значения получены от переменных) При расчете значений некоторых элементов пользовательского интерфейса изменяются:

this.Dispatcher.BeginInvoke(new Action(() => 
    { 
      this.lbl_001.Content = "someString"; 
    })); 
+0

Вы можете добавить код, который вы используете до сих пор. Поскольку многопоточность в C#/WPF может быть выполнена различными способами, и вы уже говорите о двух разных механизмах (Задачи/Параллельные). – woutervs

+0

Трудно дать вам что-либо, не видя, как ваш код в настоящее время структурирован. Мы можем делать только предположения. Случайно ожидая задачи по задержке, бессмысленно, хотя .. все это будет продолжаться синхронно. –

+1

Также, какая работа есть? Связаны ли рабочие элементы? Действительно ли они на 100% связаны с процессором, или есть ли активность ввода-вывода, вызывающая задержки? Что «висит»? Пользовательский интерфейс? Или только некоторые из задач получают свою «справедливую» долю в ЦП? Вы хотите асинхронность или параллелизм? «Задача» - для асинхронности, * не * параллельности, т. Е. он предназначен для того, чтобы вы могли выполнять много операций, не связанных с ЦП, «одновременно», без дополнительных затрат на дополнительные потоки. – Luaan

ответ

0

Как говорит @Luaan, я бы настоятельно рекомендую прочитать на async/await, ключевым моментом является его не вносит какой-либо параллелизм.

Я думаю что вы пытаетесь сделать что-то вроде простой пример ниже, где стартует CPUIntensiveMethod на пул потоков и ждать его завершения. await возвращает управление из метода Calculate (разрешая продолжить работу пользовательского интерфейса), пока задача не завершится, и в этом случае она продолжит цикл while.

private async Task Calculate() 
{ 
    while (!CTSFor_task001.IsCancellationRequested) 
    { 
     await Task.Run(CPUIntensiveMethod); 
    } 
} 
5

Позвольте мне просто написать все это как ответ. Вы смешиваете две связанные, но в конечном счете отдельные концепции (к счастью - вот почему вы можете воспользоваться различием). Обратите внимание, что это мои определения понятий - вы услышите тонны разных имен для одних и тех же вещей и наоборот.

Asynchronicity о нарушении наложенной синхронности операций (т.е. op 1 ждет op 2, который ждет op 3, который ждет op 4 ...). Для меня это более общая концепция, но в настоящее время она чаще используется для обозначения того, что я называю «присущей асинхронности», т. Е. сам алгоритм асинхронен, и мы используем только синхронное программирование, потому что нам нужно (и спасибо await и async, нам больше не нужно, yay!).

Основная мысль здесь ожидания. Я ничего не могу сделать в CPU, потому что жду результата операции ввода-вывода. Такое асинхронное программирование основано на мысли, что асинхронные операции почти бесплатны - они связаны с I/O, а не с ЦП.

Параллелизм - это особый вид общей асинхронности, в которой операции не в основном ждут друг друга. Другими словами, я не жду, я работаю .Если у меня есть четыре ядра процессора, я в идеале могу использовать четыре вычислительных потока для такого вида обработки - в идеальном мире мой алгоритм будет линейно масштабироваться с количеством доступных ядер.

С асинхронностью (ожидания), используя больше потоков, улучшит кажущуюся скорость независимо от количества доступных логических ядер. Это связано с тем, что в 99% случаев код фактически не работает, он просто ждет.

С параллелизмом (), используя больше потоков, напрямую привязывается к количеству доступных рабочих сердечников.

Линии размыты a лот. Это из-за того, что вы, возможно, даже не знаете, происходит, например, процессор (и компьютер в целом) невероятно асинхронен сам по себе - видимая синхронность, которую он показывает, только там, чтобы вы могли синхронно писать код; все оптимизации и асинхронность ограничены тем, что на выходе все снова синхронно. Если ЦП должен был ждать данные из памяти каждый раз, когда вы делаете i ++, неважно, работал ли ваш процессор на частоте 3 ГГц или 100 МГц. Ваш замечательный 3 ГГц процессор будет сидеть там без дела в 99% случаев.

С учетом этого ваши расчетные задачи связаны с ЦП. Они должны выполняться с использованием параллелизма, потому что они выполняют работу. С другой стороны, UI связан с I/O, и он должен использовать асинхронный код.

В действительности, все ваши методы async Calculate делает это, что он маскирует тот факт, что это не фактически неотъемлемо асинхронный. Вместо этого вы хотите, чтобы запускал асинхронно с I/O.

Другими словами, это не метод Calculate, который является асинхронным. Это пользовательский интерфейс, который хочет, чтобы это выполнялось асинхронно для себя. Удалите все, что Task.Run беспорядок оттуда, он не принадлежит.

Что делать дальше? Это зависит от вашего варианта использования. В принципе, существует два сценария:

Вы хотите, чтобы задачи всегда выполнялись всегда в фоновом режиме от начала и до конца. В этом случае просто создайте поток для каждого из них и вообще не используйте Task. Вы также можете изучить некоторые параметры, такие как очередь производителей-потребителей и т. Д., Чтобы оптимизировать фактическое время выполнения различных возможных задач расчета. Фактическая реализация довольно тесно связана с тем, что вы на самом деле обрабатываете.

Или вы хотите запустить задачу над действием пользовательского интерфейса, а затем работать с результирующими значениями в методе пользовательского интерфейса, который запустил их , когда результаты будут готовы.. В этом случае, await наконец приходит играть:

private btn_Click(object sender, EventArgs e) 
{ 
    var result = await Task.Run(Calculate); 

    // Do some (little) work with the result once we get it 
    tbxResult.Text = result; 
} 

async ключевое слово на самом деле не имеет места в коде вообще.

Надеюсь, теперь это более понятно, не стесняйтесь задавать больше вопросов.

1

Так что вы на самом деле ищете, это разъяснение хорошей практики, чтобы максимизировать производительность, сохраняя при этом отзывчивый интерфейс. Как пояснил Luaan, разделы async и await в вашем предложении не помогут вашей проблеме, а Task.Run не подходит для вашей работы; использование потоков - лучший подход.

Определите массив потоков для запуска по одному на каждом логическом процессоре. Распределите данные своей задачи между ними и контролируйте 20 повторяющихся вычислений с помощью BufferBlock, представленной в TPL DataFlow library.

Чтобы сохранить пользовательский интерфейс отзывчивым, я предлагаю два подхода:

  1. Ваших расчеты требуют много обновлений част интерфейса: Put их необходимой информации об обновлении в очереди и обновлять их в случае таймера.
  2. Ваши расчеты спроса дефицитные обновления пользовательского интерфейса: Обновление пользовательского интерфейса с помощью метода вызова, как Control.BeginInvoke
Смежные вопросы