Разница между TPL и async / await (Обработка streamов)

Попытка понять разницу между TPL и async / await когда дело доходит до создания streamов.

Я считаю, что TPL ( TaskFactory.StartNew ) работает аналогично ThreadPool.QueueUserWorkItem в том, что он приостанавливает работу над streamом в пуле streamов. Это, конечно, если вы не используете TaskCreationOptions.LongRunning который создает новый stream.

Я думал, что async / await будет работать так же существенно:

TPL:

 Factory.StartNew( () => DoSomeAsyncWork() ) .ContinueWith( (antecedent) => { DoSomeWorkAfter(); },TaskScheduler.FromCurrentSynchronizationContext()); 

Async / Await :

 await DoSomeAsyncWork(); DoSomeWorkAfter(); 

были бы идентичны. Из того, что я читал, кажется, что async / await только «иногда» создает новый stream. Итак, когда он создает новый stream и когда он не создает новый stream? Если вы имели дело с портами ввода-вывода IO, я вижу, что вам не нужно создавать новый stream, но в противном случае я бы подумал, что это нужно. Я думаю, что мое понимание FromCurrentSynchronizationContext всегда было немного нечетким. Я всегда понимал, что это был, по сути, stream пользовательского интерфейса.

Я считаю, что TPL (TaskFactory.Startnew) работает аналогично ThreadPool.QueueUserWorkItem, поскольку он ставит в очередь работу над streamом в пуле streamов.

В значительной степени .

Из того, что я читал, кажется, что async / await только «иногда» создает новый stream.

На самом деле этого никогда не бывает. Если вы хотите multithreading, вы должны реализовать ее самостоятельно. Появился новый метод Task.Run который просто сокращен для Task.Factory.StartNew , и это, вероятно, самый распространенный способ запуска задачи в пуле streamов.

Если вы имели дело с портами ввода-вывода IO, я вижу, что вам не нужно создавать новый stream, но в противном случае я бы подумал, что это нужно.

Бинго. Поэтому такие методы, как Stream.ReadAsync , фактически создают оболочку Task вокруг IOCP (если Stream имеет IOCP).

Вы также можете создавать некоторые не-I / O, не-ЦП «задачи». Простым примером является Task.Delay , который возвращает задание, которое завершается через некоторый период времени.

Приятная вещь о async / await заключается в том, что вы можете поставить в очередь некоторую работу в пул streamов (например, Task.Run ), выполнить некоторую операцию с привязкой к I / O (например, Stream.ReadAsync ) и выполнить некоторую другую операцию (например, Task.Delay ) … и это все задачи! Их можно Task.WhenAll или использовать в таких комбинациях, как Task.WhenAll .

Любой метод, который возвращает Task может быть await ed – он не должен быть async методом. Таким образом, Task.Delay и I / O связаны с TaskCompletionSource для создания и завершения задачи – единственное, что делается в пуле streamов, – это фактическое завершение задачи при возникновении события (тайм-аут, завершение ввода-вывода и т. Д.).

Я думаю, что мое понимание FromCurrentSynchronizationContext всегда было немного нечетким. Я всегда понимал, что это был, по сути, stream пользовательского интерфейса.

Я написал статью о SynchronizationContext . Большую часть времени SynchronizationContext.Current :

  • является контекстом пользовательского интерфейса, если текущий stream является streamом пользовательского интерфейса.
  • представляет собой контекст запроса ASP.NET, если текущий stream обслуживает запрос ASP.NET.
  • это контекст пула streamов в противном случае.

Любой stream может установить свой собственный SynchronizationContext , поэтому есть исключения из правил выше.

Обратите внимание, что по умолчанию Task awaiter будет планировать оставшуюся часть метода async в текущем SynchronizationContext если он не равен null ; в противном случае он переходит к текущему TaskScheduler . Сегодня это не так важно, но в ближайшем будущем это будет важное различие.

Я написал свою собственную async / await интро в своем блоге, и Стивен Туб недавно опубликовал замечательный async / await FAQ .

Что касается «параллелизма» и «многопоточности», см. Этот связанный вопрос SO . Я бы сказал, что async включает параллелизм, который может быть или не быть многопоточным. Это легко использовать в await Task.WhenAll или await Task.WhenAny для параллельной обработки, и если вы явно не используете пул streamов (например, Task.Run или ConfigureAwait(false) ), то вы можете выполнять несколько параллельных операций на этапе (например, несколько операций ввода-вывода или других типов, таких как Delay ), и нет необходимости в streamе. Я использую термин «однопоточный параллелизм» для такого сценария, хотя на узле ASP.NET вы можете фактически «с нулевым параллелизмом». Это довольно мило.

async / await в основном упрощает методы ContinueWith (Continuations in Continuation Passing Style )

Он не вводит параллелизм – вам все равно придется сделать это самостоятельно (или использовать версию метода framework для Async).

Итак, версия C # 5 будет:

 await Task.Run( () => DoSomeAsyncWork() ); DoSomeWorkAfter(); 
  • В чем разница между атомными / летучими / синхронизированными?
  • Нечетная печать с использованием нити
  • вилка в многопоточной программе
  • Async WebApi Thread.CurrentCulture
  • Блокирует Console.WriteLine?
  • C # версия синхронизированного ключевого слова java?
  • Doxygen медленный
  • Почему в OpenMP запрещен оператор! =?
  • Использование памяти в C #
  • Убедитесь, что синхронизированные блокировки Java выполнены в порядке?
  • Как прервать Console.ReadLine
  • Давайте будем гением компьютера.