Подтвердить что ты не робот

TaskCompletionSource - Попытка понять бессетевую работу async

Я пытаюсь понять цель TaskCompletionSource и ее отношение к работе async/threadless. Я думаю, что у меня есть общая идея, но я хочу убедиться, что мое понимание верное.

Сначала я начал изучать параллельную библиотеку задач (TPL), чтобы выяснить, был ли хороший способ создать свою собственную работу без потоков/асинхронных операций (скажем, вы пытаетесь улучшить масштабируемость вашего сайта ASP.NET) и понимаете TPL выглядит так, что это будет очень важно в будущем (async/await). Это привело меня к TaskCompletionSource.

С моей точки зрения, похоже, что добавление TaskCompletionSource к одному из ваших классов на самом деле не так сильно влияет на создание асинхронного кодирования; если вы все еще выполняете код синхронизации, вызов вашего кода будет заблокирован. Я думаю, что это справедливо и для API-интерфейсов Microsoft. Например, скажем, в DownloadStringTaskAsync off класса WebClient, любой код установки/синхронизации, который они выполняют, будет блокироваться. Код, который вы выполняете, должен запускаться в каком-то потоке, либо в текущем потоке, либо вам придется откручивать новый.

Таким образом, вы используете TaskCompletionSource в своем собственном коде, когда вы вызываете другие вызовы async от Microsoft, поэтому клиенту ваших классов не нужно создавать новый поток для вашего класса, чтобы он не блокировался.

Не знаете, как Microsoft внутренне выполняет свои асинхронные API. Например, существует новый async метод SqlDataReader для .Net 4.5. Я знаю, что есть порты ввода-вывода IO. Я думаю, что это абстракция более низкого уровня (С++?), Которая, вероятно, большинство разработчиков С# не будет использовать. Не уверен, что завершение ввода IO портов будет работать для сетевых или сетевых вызовов (HTTP) или если оно используется только для файла IO.

Итак, вопрос в том, правильно ли я в своем понимании правильно? Есть ли определенные вещи, которые я представил неправильно?

4b9b3361

Ответ 1

TaskCompletionSource используется для создания объектов Task, которые не выполняют код.

Они используются совсем другими API-интерфейсами новых асинхронных программ Microsoft - в любое время при работе с асинхронными операциями ввода-вывода (или другими асинхронными операциями, отличными от ЦП, например тайм-аутом). Кроме того, любой метод async Task, который вы пишете, будет использовать TCS для завершения возвращаемого Task.

У меня есть сообщение в блоге Создание задач, в котором обсуждаются различные способы создания экземпляров Task. Он написан с точки зрения async/await (а не перспективы TPL), но он по-прежнему применяется здесь.

Также см. Стивен Туб, отличные сообщения:

Ответ 2

Мне нравится объяснение, которое было представлено в http://tutorials.csharp-online.net/TaskCompletionSource

(извините, ссылка может быть мертва в данный момент)

Первые два абзаца ниже

Мы видели, как Task.Run создает задачу, выполняющую делегат на пустая (или не объединенная) нить. Другой способ создания задачи - TaskCompletionSource.

TaskCompletionSource позволяет создать задачу из любой операции, которая начинается и заканчивается спустя некоторое время. Он работает, предоставляя вам "рабов", задание, которое вы вручную указываете при завершении операции или неисправностей. Это идеально подходит для работы с I/O-привязкой: вы получаете все преимущества задач (с их способностью распространять возвращаемые значения, исключения, и продолжения), не блокируя нить на время операции.

Чтобы использовать TaskCompletionSource, вы просто создаете экземпляр класса. Это предоставляет свойство Task, которое возвращает задачу, на которую вы можете подождать и присоединяйте продолжения - так же, как и к любой другой задаче. Задание, однако, полностью контролируется объектом TaskCompletionSource через следующие методы:

public class TaskCompletionSource<TResult> 
{ 
 public void SetResult(TResult result); 
 public void SetException (Exception exception); 

 public void SetCanceled();   
 public bool TrySetResult (TResult result); 
 public bool TrySetException (Exception exception); 
 public bool TrySetCanceled();
 ... 
}

Вызов любого из этих методов сигнализирует задачу, помещая ее в завершено, повреждено или отменено состояние (мы рассмотрим последнее в раздел "Отмена" ). Вы должны назвать один из этих методов ровно один раз: если вызывается снова, SetResult, SetException или SetCanceled выдает исключение, тогда как методы Try * возвращают false.

Следующий пример печатает 42 после ожидания в течение пяти секунд:

var tcs = new TaskCompletionSource<int>();
new Thread (() =>     {
                       Thread.Sleep (5000); 
                       tcs.SetResult (42); 
                      })    
           .Start();   
Task<int> task = tcs.Task;    // Our "slave" task. 
Console.WriteLine(task.Result);  // 42

Другие интересные цитаты

Реальная сила TaskCompletionSource заключается в создании задач, которые не связать потоки.

.. и позже

Наше использование TaskCompletionSource без потока означает, что поток участвует только в том случае, если продолжение начинается через пять секунд. Мы может продемонстрировать это, запустив сразу 10 000 из этих операций без ошибок или чрезмерного потребления ресурсов: