С практическим асинхронным программированием столкнулся относительно недавно, и, изучая тему детальнее, назрел вопрос:
При создании задачи с помощью Task.Factory.StartNew (с параметром TaskCreationOptions.LongRunning) поток для задачи выбирается НЕ из пула.
Какой поток выбирается при создании с помощью TaskCompletionSource - из пула или не из пула?
P.S. Читал, мол, эти два способа эквивалентны... Но хочется разъяснтить очень важную деталь: какой поток выбирается при втором способе?
Никакой.
Task — это не обязательно «код, бегущий в каком-то потоке». Это не абстракция над методом, бегущем непонятно где. Это лишь формальное обещание когда-либо предоставить результат. Работает ли над этим результатом один поток, несколько, или вообще ни одного — это внутренняя подробность, скрытая внутри Task'а, и недоступная наблюдателю.
Таски, создаваемые через Task.Run или TaskFactory.CreateNew, действительно являются методом, бегущим в том или ином потоке. Но это не является общим свойством всех тасков. Таск имеет право не бежать нигде.
Например, вы можете создать TaskCompletionSource, запустить таймер, и по приходу таймера завершить задачу. При этом, понятно, ваш таск не будет бежать ни в каком потоке.
Дополнительное чтение по теме: Нет никакого потока (Stephen Cleary, перевод Андрея Часовских).
Класс 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;
}
Продвижение своими сайтами как стратегия роста и независимости