Страницы с тегами : TPL

Блеск и нищета Task Parallel Library

Task Parallel Library (пространство имен System.Threading.Tasks) появилась еще в .NET 4, но большой популярностью не пользовалась. На подходе компилятор C# 5, который поддерживает конструкцию async\await. В скомпилированом коде async метод превращается в метод возвращающий Task\Task<T>.  Поэтому в скором времени использование TPL станет повсеместным.

Task Parallel Library – имеет очень мощные механизмы: вложенные (nested) задачи, локальные очереди для потоков, чтобы уменьшить латентность, work-stealing алгоритмы для работы, кучи опций запуска задач и продолжений, различные планировщики. Все создано в лучших традициях оптимизации асинхронного кода.

Но, TPL создавался до мозга костей практиками и цели сделать библиотеку удобной для потребителей даже не ставилось судя по всему.

  1. Как это не смешно, то в стандартной библиотеке нету метода, позволяющего обернуть значение T в Task<T>. (Только в .NET 4.5 появился Task.FromResult)
  2. Сам объект Task представляет из себя “задачу”, которая может быть как еще не запущена, так и уже выполняться.  Поэтому работа с разными Task_ами будет осуществляться по-разному.
  3. Task не является immutable объектом, метод ContinueWith изменяет саму задачу.
  4. Функция ContinueWith срабатывает при любом завершении задачи, в том числе отмене или ошибке. Необходимо каждый раз указывать флаги.
  5. Исключения внутри задач собираются в один объект, что затрудняет структурированную их обработку.
  6. Метод ContinueWith принимает Func<Task, T>, а не Func<Task, Task>. Это значит что единственный способ связать две задачи – создать вложенную (nested), что может привести к переполнению стека при завершении цепочки вложенных задач.

Последний пункт особенно актуален.  Даже был сделан extension-метод Unwrap, который позволяет писать код в виде:

var task = SomeFuncReturningTask(...)
                .ContinueWith(t => SomeOtherFuncReturningTask(t.Result))
                .Unwrap().ContinueWith(...)
                .Unwrap().ContinueWith(...);