Разница между TPL и async / await (Обработка streamов)
Попытка понять разницу между TPL и async
/ await
когда дело доходит до создания streamов.
Я считаю, что TPL ( TaskFactory.StartNew
) работает аналогично ThreadPool.QueueUserWorkItem
в том, что он приостанавливает работу над streamом в пуле streamов. Это, конечно, если вы не используете TaskCreationOptions.LongRunning
который создает новый stream.
Я думал, что async
/ await
будет работать так же существенно:
- Безопасно ли использовать логический флаг, чтобы остановить stream из C #
- ключевое слово блокировки в C #
- Очередь процесса с многопоточным или задачами
- Надуть представление в фоновом streamе
- Реализации Java Queue, какой?
TPL:
Factory.StartNew( () => DoSomeAsyncWork() ) .ContinueWith( (antecedent) => { DoSomeWorkAfter(); },TaskScheduler.FromCurrentSynchronizationContext());
Async
/ Await
:
await DoSomeAsyncWork(); DoSomeWorkAfter();
были бы идентичны. Из того, что я читал, кажется, что async
/ await
только «иногда» создает новый stream. Итак, когда он создает новый stream и когда он не создает новый stream? Если вы имели дело с портами ввода-вывода IO, я вижу, что вам не нужно создавать новый stream, но в противном случае я бы подумал, что это нужно. Я думаю, что мое понимание FromCurrentSynchronizationContext
всегда было немного нечетким. Я всегда понимал, что это был, по сути, stream пользовательского интерфейса.
- Синхронизация и System.out.println
- Как правильно прочитать поле Interlocked.Increment' int?
- Монитор против Mutex в c #
- Как защитить ресурсы, которые могут использоваться в многопоточной или асинхронной среде?
- Тема против ThreadPool
- Можно ли использовать мьютекс в многопроцессорном случае в Linux / UNIX?
- kill -3, чтобы получить java thread dump
- Ожидание выполнения нескольких streamов в Java
Я считаю, что 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();