我正在评估Async CTP。
如何在另一个线程池的线程上开始执行异步函数?
static async Task Test()
{
// Do something, await something
}
static void Main( string[] args )
{
// Is there more elegant way to write the line below?
var t = TaskEx.Run( () => Test().Wait() );
// Doing much more in this same thread
t.Wait(); // Waiting for much more then just this single task, this is just an example
}
答案 0 :(得分:52)
我是新的(我的处女帖子)Stack Overflow,但我很高兴你问起Async CTP,因为我正在微软的团队中工作:)
我想我明白你的目标是什么,并且你正确地做了几件事,让你到那儿。
我认为你想要的是什么:
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
类型。相反,当它们冲突时,操场API被命名为FooEx。
为什么我们将其中一些Run(...)
和一些RunEx(...)
命名为?原因是由于我们在发布CTP时尚未完成的方法重载的重新设计。在我们当前的工作代码库中,我们实际上必须稍微调整C#方法重载规则,以便Async Lambdas正确的事情发生 - 它可以返回void
,Task
或Task<T>
问题是,当异步方法或lambdas返回Task
或Task<T>
时,它们实际上在返回表达式中没有外部任务类型,因为任务是作为一部分自动为您生成的方法或lambda的调用。这在我们看来似乎是正确的代码清晰度体验,尽管之前确实使事情完全不同,因为通常返回语句的表达式可以直接转换为方法或lambda的返回类型。
因此,async void
lambdas和async Task
lambdas都支持return;
而没有参数。因此需要澄清方法重载决策以决定选择哪一个。因此,您同时拥有Run(...)和RunEx(...)的唯一原因是,在PDC 2010命中时,我们将确保为Async CTP的其他部分提供更高质量的支持。 / p>
如何考虑异步方法/ lambdas
我不确定这是否是一个混乱点,但我想我会提到它 - 当你编写异步方法或异步lambda时,它可以承担调用它的任何人的某些特征。这取决于两件事:
等待的CTP设计和我们当前的内部设计都是基于模式的,因此API提供商可以帮助充实您可以“等待”的一系列充满活力的东西。这可能会根据您正在等待的类型而有所不同,其常见类型为Task
。
Task
等待实现是非常合理的,并且按照当前线程的SynchronizationContext
来决定如何推迟工作。如果您已经在WinForms或WPF消息循环中,那么您的延迟执行将返回到同一消息循环(就像您使用BeginInvoke()
“其余方法”一样)。如果你等待一个Task并且你已经在.NET线程池中,那么“你的方法的其余部分”将在其中一个线程池线程上恢复(但不一定完全相同),因为它们被合并为开头很可能你很乐意使用第一个可用的池线程。
关于使用Wait()方法的注意事项
在您使用的样本中:
var t = TaskEx.Run( () => Test().Wait() );
它的作用是:
'await'运算符的主要好处是它允许您添加稍后执行的代码 - 但不会阻塞原始线程。在线程池的情况下,您可以实现更好的线程利用率。
如果您对VB或C#的异步CTP有其他疑问,请告诉我,我很乐意听到它们:)
答案 1 :(得分:5)
通常由返回Task
的方法确定它运行的位置,如果它正在开始真正的新工作,而不是仅仅依靠其他东西。
在这种情况下,它看起来不像真的希望Test()
方法是异步的 - 至少,你不是使用这个事实这是异步的。你只是在另一个线程中启动... Test()
方法可以完全同步,你可以使用:
Task task = TaskEx.Run(Test);
// Do stuff
t.Wait();
这不需要任何异步CTP优点。
答案 2 :(得分:2)
如果这不是控制台应用程序,那将会是。例如,如果在Windows窗体应用程序中执行此操作,则可以执行以下操作:
// Added to a button click event, for example
public async void button1_Click(object sender, EventArgs e)
{
// Do some stuff
await Test();
// Do some more stuff
}
但是,控制台中没有默认SynchronizationContext
,因此无法按照您的预期运行。在控制台应用程序中,您需要显式获取任务,然后在最后等待。
如果您在Windows窗体,WPF甚至WCF服务的UI线程中执行此操作,将会有一个有效的SynchronizationContext,用于正确地封送结果。但是,在控制台应用程序中,当在await
调用时“返回”控制时,程序将继续,并立即退出。这往往会弄乱一切,并产生意想不到的行为。