2013-11-12 3 views
1

У меня 1-ядерная машина, и я бы хотел улучшить свою производительность кода с помощью async и ждать. Код имеет две основные части. первая операция ввода-вывода. (чтение из очереди служебной шины azure для нескольких sessionId), во-вторых, обработка данных - процессор тяжелый. я обернут метод DequeueAsync в методе асинхронного который возвращает задачу: тяжелый методЛучшая производительность с использованием async и ожидания

private async Task<SomeReturnValue> AcceptFromQueueAsync(){ 
    try{ 
     SomeReturnValue result = await DequeueAsync.configureAwait(false); 
     return SomeReturnValue; 
    } 
    catch{ 
    //logging and stuff 
    } 

Процессора синхронизация: DoSyncWork() Так как вторая часть процессора тяжелый я не хочу, чтобы использовать параллелизм (на самом деле не может ...) Часть ЦП может начинаться только тогда, когда заканчивается часть ввода-вывода. Учитывая приведенное выше, следующая реализация - путь к 1 компьютеру с процессором?

private void AcceptAndProcessWrapper(){ 
    //Count is some cosnt defined outside the method 
    _acceptTasks = new List<Task<SomeReturnValue>>(); 
    for (var i = 0; i < Count; i++) 
    { 
        _acceptTasks.Add(AcceptFromQueueAsync()); 
     } 
     //The use of list is for convince in processing 
     Task.WaitAll(_acceptTasks.ToArray()); 
     //The CPU part 
     Task.Run(DoSyncWork).Wait(); 
} 

Я знаю, что я мог бы не использовать Task.Run() для синхронизации части, но я хочу, чтобы позволить реализацию функции на нескольких ядрах (Запустив несколько задач с помощью Task.Run() и удерживать их в массив) Будет ли реализация выше. (Многократные вызовы метода async, который возвращает задачу) улучшают производительность? Или мне нужно запустить новую задачу для каждого асинхронного вызова, например Task.Run (AcceptFromQueueAsync)?

+1

Звуки для меня, как вы можете посмотреть в TPL DataFlow. –

ответ

2

Код, который у вас есть, действительно будет выполнять асинхронную декуляцию параллельно. Он запустит сразу все асинхронные задачи, а затем дождитесь, пока они все сделают, чтобы продолжить.

Добавление дополнительного звонка в Task.Run не поможет. Запуск асинхронной задачи в другом потоке просто добавляет дополнительные накладные расходы без добавленной стоимости. Task.Run должен использоваться для запуска Работа с привязкой к ЦП в другом потоке, а не асинхронная работа в другом потоке.

0

Выполнение первой части асинхронно может иметь смысл, зависит, у нее есть Async в названии, которое предполагает, что оно не блокируется в любом случае, в этом случае нет необходимости, но, безусловно, нет необходимости запускать DoSyncWork асинхронно, поскольку его просто 1, и вы ждете его завершения.

1

Говоря о производительности с Задачей (если вы используете ее в будущем с DoSyncWork), вы должны также иметь в виду, что Task.Run использует ThreadPool по умолчанию, но потоки из пула потоков скорее ожидают сделать быстрые и малые Работа. Если задачи действительно некоторые «тяжелые» те, вы должны рассмотреть возможность запуска их во вновь создаваемых потоков, которые могут быть также вынуждены следующим:

new Task(() => { }, TaskCreationOptions.LongRunning); 

EDIT:

После некоторого разговора в commeting ниже, я хотел бы очистить вещи немного больше.

В настоящее время у Task.Run(DoSyncWork).Wait(); действительно нет смысла (даже больше времени для выполнения задачи может потребоваться дополнительное время (даже от ThreadPool), но если вы хотите использовать несколько ядер в будущем, вам, очевидно, следует переместите эту задачу в другой поток для запуска (и если это действительно тяжелый процессор, рассмотрите задачу как «LongRunning») (если это конечно необходимо для вашего приложения (не уверен, что у вас есть тип приложения)) В этом случае по-прежнему нет необходимости сразу звонить .Wait().

+0

Работа * не * длинный бег. Запуск асинхронной задачи занимает почти не время, даже если это долгое время до ее завершения. Нет необходимости вручную создавать такую ​​задачу, как это, и не нужно, чтобы она была «длинной». – Servy

+1

Ну, это довольно странно, что такой высокий рейтинг говорит такие слова. ThreadPool (помимо его преимуществ) также имеет и недостатки, и это довольно широко известно, что если ThreadPool заканчивается из потоков и создает новые потоки, он может даже занимать до 500 мс (!), Что несравнимо с новым временем создания Thread. Пожалуйста, прочитайте также следующую статью: http://stackoverflow.com/questions/9200573/threadpool-queueuserworkitem-vs-task-factory-startnew. – Agat

+0

Все это * нерелевантно * к ситуации здесь. ** Операция не работает **. Для запуска потребуется всего несколько микросекунд, потому что это просто * запуск задачи * и ** не ** ожидание ее завершения. Включение этой работы в поток пула потоков совершенно не нужно в первую очередь, и если вы решите сделать это, по какой-то причине, это, безусловно, не займет много времени; это будет невероятно быстро *. – Servy

0

Я использую шаблон, похожий на это, чтобы попытаться сохранить IO и CPU собирается как можно больше

public async void DoWork() 
{ 
    Task cpuBoundTask = null; 
    Task ioBoundTask = null; 

    while(true) 
    { 
     ioBoundTask = DoIOBoundStuff(); 
     var ioResult = await ioBoundTask; 

     if(cpuBoundTask != null) 
     { 
      await cpuBoundTask; 
     } 
     cpuBoundTask = DoCpuBoundStuff(ioResult); 
    } 
} 
Смежные вопросы