我是 Stack Overflow 的新手(我的处女帖),但我很高兴你在问异步 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 与 Task.RunEx
因为这个 CTP 安装在 .NET 4.0 之上,所以我们不想修补 mscorlib 中的实际 System.Threading.Tasks.Task
类型。相反,当 Playground API 发生冲突时,它们被命名为 FooEx。
为什么我们命名其中一些Run(...)
和一些RunEx(...)
?原因是我们在发布 CTP 时还没有完成方法重载的重新设计。在我们当前工作的代码库中,我们实际上不得不稍微调整 C# 方法重载规则,以便 Async Lambda 发生正确的事情——它可以返回void
、Task
或Task<T>
.
问题是,当异步方法或 lambda 返回Task
orTask<T>
时,它们实际上在返回表达式中没有外部任务类型,因为该任务是作为方法或 lambda 调用的一部分自动为您生成的。在我们看来,这对代码清晰来说是一种正确的体验,尽管这确实使事情变得完全不同,因为通常 return 语句的表达式可以直接转换为方法或 lambda 的返回类型。
因此,异步void
lambda 和异步Task
lambda 都支持return;
不带参数。因此,需要澄清方法重载决议以决定选择哪一个。因此,您同时拥有 Run(...) 和 RunEx(...) 的唯一原因是,我们将确保在 PDC 2010 发布时为 Async CTP 的其他部分提供更高质量的支持。
如何考虑异步方法/lambdas
我不确定这是否是一个混淆点,但我想我会提到它 - 当您编写异步方法或异步 lambda 时,它可能具有调用它的人的某些特征。这取决于两件事:
- 您正在等待的类型
- 可能还有同步上下文(取决于上面)
await 的 CTP 设计和我们当前的内部设计都非常基于模式,因此 API 提供者可以帮助充实一组您可以“等待”的充满活力的东西。这可能因您正在等待的类型而异,常见的类型是Task
.
Task
的 await 实现是非常合理的,并按照当前线程的SynchronizationContext
来决定如何延迟工作。如果您已经在 WinForms 或 WPF 消息循环中,那么您的延迟执行将在同一个消息循环中返回(就像您使用BeginInvoke()
“其余方法”一样)。如果您等待一个任务并且您已经在 .NET 线程池上,那么“您的方法的其余部分”将在其中一个线程池线程上恢复(但不一定完全相同),因为它们从一开始就被池化并且您很可能很乐意使用第一个可用的池线程。
注意使用 Wait() 方法
在您使用的示例中:
var t = TaskEx.Run( () => Test().Wait() );
这样做是:
- 在周围的线程中同步调用TaskEx.Run(...) 在线程池上执行一个lambda。
- 为 lambda 指定了一个线程池线程,它调用您的异步方法。
- 从 lambda 调用异步方法 Test()。因为 lambda 在线程池上执行,所以 Test() 中的任何延续都可以在线程池中的任何线程上运行。
- lambda 实际上并没有腾出该线程的堆栈,因为它没有等待。在这种情况下,TPL 的行为取决于 Test() 是否在 Wait() 调用之前实际完成。但是,在这种情况下,您很有可能会在等待 Test() 在不同线程上完成执行时阻塞线程池线程。
这是“等待”运算符的主要好处是它允许您添加稍后执行的代码 - 但不会阻塞原始线程。在线程池的情况下,可以实现更好的线程利用率。
如果您对 VB 或 C# 的异步 CTP 有其他问题,请告诉我,我很乐意听到:)