Разница в выбранном потоке между TaskCompletionSource и Task.Factory.StartNew

392
08 августа 2017, 13:28

С практическим асинхронным программированием столкнулся относительно недавно, и, изучая тему детальнее, назрел вопрос:

При создании задачи с помощью Task.Factory.StartNew (с параметром TaskCreationOptions.LongRunning) поток для задачи выбирается НЕ из пула.
Какой поток выбирается при создании с помощью TaskCompletionSource - из пула или не из пула? P.S. Читал, мол, эти два способа эквивалентны... Но хочется разъяснтить очень важную деталь: какой поток выбирается при втором способе?

Answer 1

Никакой.

Task — это не обязательно «код, бегущий в каком-то потоке». Это не абстракция над методом, бегущем непонятно где. Это лишь формальное обещание когда-либо предоставить результат. Работает ли над этим результатом один поток, несколько, или вообще ни одного — это внутренняя подробность, скрытая внутри Task'а, и недоступная наблюдателю.

Таски, создаваемые через Task.Run или TaskFactory.CreateNew, действительно являются методом, бегущим в том или ином потоке. Но это не является общим свойством всех тасков. Таск имеет право не бежать нигде.

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

Дополнительное чтение по теме: Нет никакого потока (Stephen Cleary, перевод Андрея Часовских).

Answer 2

Класс TaskCompletionSource<T> - это класс позволяющий создать задачу Task, которой вы управляете как марионеткой. Ее можно в любой момент сделать успешно завершившейся или записать в нее исключение и тем самым сказав, что она завершилась с ошибкой. Данный класс можно применять, например, при переводе с паттерна IAsyncResult на TAP.

 public static Task<IPHostEntry> GetHostEntryAsync(string hostNameOrAddress)
 {
     var tcs = new TaskCompletionSource<IPHostEntry>();
     Dns.BeginGetHostEntry(hostNameOrAddress, asyncResult =>
     {
         try
         {
             IPHostEntry result = Dns.EndGetHostEntry(asyncResult);
             tcs.SetResult(result);
         }
         catch(Exception e)
         {
             tcs.SetException(e);
         }
    }, null);
    return tcs.Task;
}
READ ALSO
Связывание Entity Framework Core SqLite с WPF

Связывание Entity Framework Core SqLite с WPF

Как связать WPF с EF Core Sqlite и что прописывать в appconfig? Если нельзя связать

339
c# reportviwer передача параметров в отчет

c# reportviwer передача параметров в отчет

Здравствуйте, назрел вопрос по передаче параметров в отчет

295
Как обновить checkbox в ASP.NET

Как обновить checkbox в ASP.NET

У меня есть два паршала, в одном список, а в другом открываеться более детальная информация после того как нажать на запись в спискеКогда...

349
Работа с командной строкой C#

Работа с командной строкой C#

Первое Проблема

477