在另一个线程中运行异步函数
我正在评估异步 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
}
I'm evaluating the Async CTP.
How can I begin execution of an async function on another thread pool's thread?
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
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我是 Stack Overflow 的新手(我的第一篇文章),但我很高兴您询问有关异步 CTP 的问题,因为我是 Microsoft 的团队成员之一:)
我想我明白您的目标因为,为了实现这一目标,您需要做一些正确的事情。
我认为您想要的是:
Task.Run 与 Task.RunEx
因为此 CTP 安装在 .NET 4.0 之上,所以我们不想修补实际
System.Threading.Tasks.Task
在 mscorlib 中键入。相反,当 Playground API 发生冲突时,它们会被命名为 FooEx。为什么我们将其中一些命名为
Run(...)
和一些RunEx(...)
?原因是我们发布 CTP 时尚未完成方法重载的重新设计。在我们当前的工作代码库中,我们实际上必须稍微调整 C# 方法重载规则,以便异步 Lambda 发生正确的事情 - 它可以返回void
、Task
、或任务
。问题是,当异步方法或 lambda 返回
Task
或Task
时,它们实际上在返回表达式中没有外部任务类型,因为任务是作为方法或 lambda 调用的一部分自动为您生成。在我们看来,这似乎是代码清晰性的正确体验,尽管这确实使事情变得非常不同,因为通常 return 语句的表达式可以直接转换为方法或 lambda 的返回类型。因此,async
void
lambda 和 asyncTask
lambda 都支持不带参数的return;
。因此,需要对方法重载决策进行澄清,以决定选择哪一个。因此,同时拥有 Run(...) 和 RunEx(...) 的唯一原因是,我们可以确保在 PDC 2010 到来时为异步 CTP 的其他部分提供更高质量的支持。如何思考异步方法/lambda
我不确定这是否是一个混淆点,但我想我会提到它 - 当你编写异步方法或异步 lambda 时,它可以呈现调用它的人的某些特征。这是基于两件事:
的 CTP 设计和我们当前的内部设计都是非常基于模式的,因此 API 提供者可以帮助充实一个充满活力的模式。一系列你可以“等待”的事情。这可能会根据您等待的类型而有所不同,常见的类型是
任务
。Task
的await实现非常合理,按照当前线程的SynchronizationContext
来决定如何推迟工作。如果您已经处于 WinForms 或 WPF 消息循环中,那么您的延迟执行将在同一个消息循环中返回(就好像您使用了“方法的其余部分”BeginInvoke()
) )。如果您等待一个任务并且您已经在 .NET 线程池上,那么“方法的其余部分”将在其中一个线程池线程(但不一定是完全相同的线程)上恢复,因为它们一开始就被池化并且您很可能很乐意使用第一个可用的池线程。使用 Wait() 方法的注意事项
在您使用的示例中:
var t = TaskEx.Run( () => Test().Wait() );
其作用是:
这是“await”运算符的主要好处是它允许您添加稍后执行的代码 - 但不会阻塞原始线程。在线程池的情况下,可以实现更好的线程利用率。
如果您对 VB 或 C# 的异步 CTP 有其他疑问,请告诉我,我很乐意听听:)
I'm new (my virginal post) to Stack Overflow, but I'm jazzed that you're asking about the Async CTP since I'm on the team working on it at Microsoft :)
I think I understand what you're aiming for, and there's a couple of things you're doing correctly, to get you there.
What I think you want:
Task.Run vs. Task.RunEx
Because this CTP installs on top of .NET 4.0, we didn't want to patch the actual
System.Threading.Tasks.Task
type in mscorlib. Instead, the playground APIs are named FooEx when they conflicted.Why did we name some of them
Run(...)
and some of theRunEx(...)
? The reason is because of redesigns in method overloading that we hadn't completed yet by the time we released the CTP. In our current working codebase, we've actually had to tweak the C# method overloading rules slightly so that the right thing happens for Async Lambdas - which can returnvoid
,Task
, orTask<T>
.The issue is that when async method or lambdas return
Task
orTask<T>
, they actually don't have the outer task type in the return expression, because the task is generated for you automatically as part of the method or lambda's invocation. This strongly seems to us like the right experience for code clarity, though that does make things quite different before, since typically the expression of return statements is directly convertible to the return type of the method or lambda.So thus, both async
void
lambdas and asyncTask
lambdas supportreturn;
without arguments. Hence the need for a clarification in method overload resolution to decide which one to pick. Thus the only reason why you have both Run(...) and RunEx(...) was so that we would make sure to have higher quality support for the other parts of the Async CTP, by the time PDC 2010 hit.How to think about async methods/lambdas
I'm not sure if this is a point of confusion, but I thought I'd mention it - when you are writing an async method or async lambda, it can take on certain characteristics of whoever is invoking it. This is predicated on two things:
The CTP design for await and our current internal design are both very pattern-based so that API providers can help flesh out a vibrant set of things that you can 'await' on. This can vary based on the type on which you're awaiting, and the common type for that is
Task
.Task
's await implementation is very reasonable, and defers to the current thread'sSynchronizationContext
to decide how to defer work. In the case that you're already in a WinForms or WPF message loop, then your deferred execution will come back on the same message loop (as if you usedBeginInvoke()
the "rest of your method"). If you await a Task and you're already on the .NET threadpool, then the "rest of your method" will resume on one of the threadpool threads (but not necessarily the same one exactly), since they were pooled to begin with and most likely you're happy to go with the first available pool thread.Caution about using Wait() methods
In your sample you used:
var t = TaskEx.Run( () => Test().Wait() );
What that does is:
That's the primary benefit of the 'await' operator is that it allows you to add code that executes later - but without blocking the original thread. In the thread pool case, you can achieve better thread utilization.
Let me know if you have other questions about the Async CTP for VB or C#, I'd love to hear them :)
通常由返回
Task
的方法来确定它的运行位置,是否正在开始真正的新工作,而不是仅仅依靠其他东西。在这种情况下,您似乎并不真的希望
Test()
方法是异步的 - 至少,您没有使用事实上它是异步的。您只是在不同的线程中开始工作...Test()
方法可以完全同步,您可以只使用:这不需要任何异步 CTP 的优点。
It's usually up to the method returning the
Task
to determine where it runs, if it's starting genuinely new work instead of just piggy-backing on something else.In this case it doesn't look like you really want the
Test()
method to be async - at least, you're not using the fact that it's asynchronous. You're just starting stuff in a different thread... theTest()
method could be entirely synchronous, and you could just use:That doesn't require any of the async CTP goodness.
如果这不是控制台应用程序的话,就会有。例如,如果您在 Windows 窗体应用程序中执行此操作,则可以执行以下操作:
但是,控制台中没有默认的
SynchronizationContext
,因此它不会按您期望的方式工作。在控制台应用程序中,您需要显式地获取任务,然后等待结束。如果您在 Windows 窗体、WPF 甚至 WCF 服务的 UI 线程中执行此操作,则将有一个有效的 SynchronizationContext 用于正确封送结果。然而,在控制台应用程序中,当在
await
调用中“返回”控制权时,程序会继续执行,然后立即退出。这往往会搞乱一切,并产生意想不到的行为。There would be, if this wasn't a console application. For example, if you do this in a Windows Forms application, you could do:
However, there is no default
SynchronizationContext
in a console, so that won't work the way you'd expect. In a console application, you need to explicitly grab the task and then wait at the end.If you're doing this in a UI thread in Windows Forms, WPF, or even a WCF service, there will be a valid SynchronizationContext that will be used to marshal back the results properly. In a console application, however, when control is "returned" at the
await
call, the program continues, and just exits immediately. This tends to mess up everything, and produce unexpected behavior.