Асинхронность в C# 5. Часть 1
Асинхронность в C # 5. Часть 1
Разработчики C# 2.0 поняли, что реализация логики итераторов слишком сложная. Поэтому они добавили блоки итераторов (iterator blocks). Добавили так, чтобы компилятор знал, как создать конечный автомат для хранения продолжения – «что выполнить затем» - где-то в состоянии, скрытом от пользователя, чтобы не пришлось этот код писать руками.
Они также поняли, что создание маленьких методов, использующих локальные переменные также не слишком удобно. Поэтому они добавили анонимные методы. Добавили так, чтобы компилятор знал, как преобразовать локальные переменные в замыкания, чтобы не пришлось этот код писать руками.
Разработчики C# 3.0 поняли, что написание кода, который сортирует, фильтрует, объединяет, группирует и суммирует сложные наборы данных слишком сложно. Поэтому они добавили выражения запросов (query comprehensions) и другие возможности библиотеки LINQ. Добавили так, чтобы компилятор знал, что нужно вызвать для создания запроса: деревья выражений и т.д.
Разработчики C# 4.0 поняли, взаимодействие со старыми динамическими моделями объекта слишком сложно. Поэтому они добавили тип dynamic. Добавили так, чтобы компилятор знал, как сгенерировать код во время компиляции, который будет анализироваться с помощью Dynamic Language Runtime во время выполнения.
Разработчики C# 5.0 поняли, что создание кода, работающего асинхронно, таким огромным количеством способов, слишком сложно. Его сложно анализировать, и, как мы видели, его преобразование в продолжения является сложным и приводит к коду, устройство которого скрывает его намерения.
Так продолжаться не должно.
Я рад сообщить, что появится C# 5.0 (*), и что в нем вы сможете взять этот синхронный код:
void ArchiveDocuments(List<Url> urls)
{
for(int i = 0; i < urls.Count; ++i)
Archive(Fetch(urls[i]));
}
при наличии разумной реализации методов FetchAsync и ArchiveAsync преобразовать его таким образом, чтобы использовать совместное время ожидания завершения операций, как обсуждалось в предыдущем сообщении:
async void ArchiveDocuments(List<Url> urls)
{
Task archive = null;
for(int i = 0; i < urls.Count; ++i)
{
var document = await FetchAsync(urls[i]);
if (archive != null)
await archive;
archive = ArchiveAsync(document);
}
}
А где же конечный автомат, лямбда-выражения, продолжения для проверки завершилась задача или нет? Они все на месте. Но пусть за вас весь этот код генерирует компилятор, так же, как он генерирует код блока итераторов, замыканий, деревьев выражений, выражений запросов и динамических вызовов. По сути, код на языке C# 5.0 является лишь синтаксическим сахаром для кода, представленного в предыдущем посте. Но это действительно классный сахар!
Я хочу, чтобы вы меня поняли очень четко: поведение этого кода, будет логически идентичным поведению кода из предыдущего поста. Как только задача переходит в состояние «ожидания», остаток метода устанавливается в качестве продолжения этой задачи, а управление немедленно передается вызывающему коду. После завершения задачи вызывается продолжение и метод продолжает свое выполнение с того места, где он был ранее.
Если я правильно рассчитал время публикации статьи, то Андерс анонсирует новую возможность языка на конференции PDC примерно … сейчас. Вы можете посмотреть его выступление здесь.
Мы прямо сейчас работаем над версией Community Technology Preview прототипа компилятора C# 5.0. Прототип компилятора по качеству будет соответствовать прототипу; ожидаемые возможности будут более или менее работоспособными. Это сделано для того, чтобы вы могли попробовать эти возможности, оценить их, и мы бы получили ваши отклики как можно раньше.
Я собираюсь писать об этой возможности завтра и некоторое время после этого; если вы не можете ждать или хотите попробовать этот прототип, вы можете найти дополнительную информацию и куски новенького компилятора здесь: msdn.com/vstudio/async.
И, конечно же, следуя нашей стратегии параллельной эволюции, появится Visual Basic 11 с теми же возможностями асинхронности на основе задач. Подробности читайте в блоге команды VB, или читайте об этом в блоге моего коллеги Лусиана. (Лусиан выполнил большую часть конструирования и прототипирования этой возможности как для C# так и для VB; он, а не я эксперт в этом вопросе, так что если у вас будут серьезные вопросы, то лучше спрашивать у него, а не у меня).
Завтра: await? async? Task? А что насчет AsyncThingy<T>?
(*) Мы пока не собираемся анонсировать никакие даты выхода или чего-то такого, так что даже не спрашивайте. Даже если бы я знал, а я не знаю, и даже если бы мои знания были хотя бы сколь-нибудь точны, а это не так, я бы все равно вам бы не сказал.