Я новичок (мой девственный пост) в Stack Overflow, но я потрясен, что вы спрашиваете об Async CTP, так как я в команде, работающей над этим в Microsoft:)
Мне кажется, я понимаю, к чему вы стремитесь, и есть пара вещей, которые вы делаете правильно, чтобы вы там оказались.
То, что я думаю, вы хотите:
static async Task Test()
{
// Do something, await something
}
static void Main(string[] args)
{
// In the CTP, use Task.RunEx(...) to run an Async Method or Async Lambda
// on the .NET thread pool
var t = TaskEx.RunEx(Test);
// the above was just shorthand for
var t = TaskEx.RunEx(new Func<Task>(Test));
// because the C# auto-wraps methods into delegates for you.
// Doing much more in this same thread
t.Wait(); // Waiting for much more then just this single task, this is just an example
}
Task.Run vs. Task.RunEx
Поскольку этот CTP устанавливается поверх .NET 4.0, мы не хотели исправлять фактический System.Threading.Tasks.Task
тип в mscorlib. Вместо этого API игровой площадки называются FooEx, когда они конфликтуют.
Почему мы назвали некоторых из них Run(...)
, а некоторые из RunEx(...)
? Причина в том, что произошла редизайн перегрузки методов, которую мы еще не завершили к моменту выпуска CTP. В нашей текущей рабочей кодовой базе нам фактически пришлось немного подправить правила перегрузки метода C #, чтобы с асинхронными лямбда-кодами произошла правильная ситуация, которая может возвращать void
, Task
или Task<T>
.
Проблема в том, что когда асинхронный метод или лямбда-выражения возвращают Task
или Task<T>
, они фактически не имеют внешнего типа задачи в выражении возврата, потому что задача генерируется для вас автоматически как часть метода или лямбда-вызов. Нам это кажется очень подходящим для ясности кода, хотя раньше это было совершенно иначе, поскольку обычно выражение выражений return напрямую конвертируется в тип возврата метода или лямбды.
Таким образом, и async void
lambdas, и async Task
lambdas поддерживают return;
без аргументов. Отсюда необходимость уточнения в разрешении перегрузки метода, чтобы решить, какой из них выбрать. Таким образом, единственная причина, по которой у вас есть Run (...) и RunEx (...), заключается в том, что к моменту выхода PDC 2010 мы обеспечим более качественную поддержку других частей Async CTP.
Как думать об асинхронных методах / лямбдах
Я не уверен, что это может привести к путанице, но я подумал, что упомяну об этом - когда вы пишете асинхронный метод или асинхронную лямбду, он может принимать определенные характеристики того, кто его вызывает. Это основано на двух вещах:
- Тип, который вы ожидаете
- И, возможно, контекст синхронизации (в зависимости от выше)
Дизайн CTP для await и наш текущий внутренний дизайн основаны на шаблонах, поэтому провайдеры API могут помочь в разработке яркого набора вещей, от которых вы можете «ждать». Это может варьироваться в зависимости от типа, который вы ожидаете, и общий тип для этого Task
.
Реализация ожидания
Task
очень разумна, и от нее зависит SynchronizationContext
текущего потока, чтобы решить, как отложить работу. В случае, если вы уже находитесь в цикле сообщений WinForms или WPF, ваше отложенное выполнение вернется в тот же цикл обработки сообщений (как если бы вы использовали BeginInvoke()
«остаток вашего метода»). Если вы ожидаете Задачу и уже находитесь в пуле потоков .NET, то «остаток вашего метода» возобновится в одном из потоков пула потоков (но не обязательно точно в том же), так как они были объединены для начала и Скорее всего, вы счастливы использовать первый доступный поток пула.
Предупреждение об использовании методов Wait ()
В вашем примере вы использовали:
var t = TaskEx.Run( () => Test().Wait() );
Что это делает:
- В окружающем потоке синхронно вызывается TaskEx.Run (...) для выполнения лямбды в пуле потоков.
- Поток пула потоков предназначен для лямбды и вызывает ваш асинхронный метод.
- Асинхронный метод Test () вызывается из лямбды. Поскольку лямбда выполнялась в пуле потоков, любые продолжения внутри Test () могут выполняться в любом потоке в пуле потоков.
- Лямбда на самом деле не освобождает стек этого потока, потому что его там не было.Поведение TPL в этом случае зависит от того, действительно ли Test () завершился до вызова Wait ().Однако в этом случае существует реальная возможность того, что вы будете блокировать поток пула потоков, пока он ожидает завершения выполнения Test () в другом потоке.
Это основное преимущество 'Оператор await 'заключается в том, что он позволяет добавлять код, который выполняется позже, но без блокировки исходного потока.В случае пула потоков вы можете добиться лучшего использования потоков.
Дайте мне знать, если у вас есть другие вопросы об Async CTP для VB или C #, я бы хотел их услышать:)