[英]Push async method's execution to thread pool thread
考虑这个Windows窗体代码(可以编写类似的WPF模拟代码):
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void TraceThreadInfo([CallerMemberName]string callerName = null)
{
Trace.WriteLine($"{callerName} is running on UI thread: {!this.InvokeRequired}");
}
private void DoCpuBoundWork([CallerMemberName]string callerName = null)
{
TraceThreadInfo(callerName);
for (var i = 0; i < 1000000000; i++)
{
// do some work here
}
}
private async Task Foo()
{
DoCpuBoundWork();
await Bar();
}
private async Task Bar()
{
DoCpuBoundWork();
await Boo();
}
private async Task Boo()
{
DoCpuBoundWork();
// e.g., saving changes to database
await Task.Delay(1000);
}
private async void button1_Click(object sender, EventArgs e)
{
TraceThreadInfo();
await Foo();
Trace.WriteLine("Complete.");
TraceThreadInfo();
}
}
这是Foo
/ Bar
/ Boo
方法的链,我想异步执行,而不阻塞UI线程。 这些方法类似,从某种意义上讲,所有这些方法都会产生一些CPU限制的工作并最终调用“真正的”异步操作(例如,执行一些繁重的计算,将保存结果发送到数据库)。
上面代码的输出是这样的:
button1_Click正在UI线程上运行:True
Foo在UI线程上运行:True
Bar在UI线程上运行:True
Boo在UI线程上运行:True
完成。
button1_Click正在UI线程上运行:True
所以,所有这些东西都是同步执行的。
我知道通过内置的等待来捕获当前的上下文。 所以,我想,这样调用ConfigureAwait(false)
就足够了:
private async Task Foo()
{
await Task.Delay(0).ConfigureAwait(false);
DoCpuBoundWork();
await Bar();
}
但实际上,这并没有改变任何事情。
我想知道,这怎么可以“推”到线程池线程,假设,在button1_Click
方法结束时我需要返回到UI线程?
编辑 。
当参数为0
时, Task.Delay(0)
实际上优化了调用(感谢@usr为注释)。 这个:
private async Task Foo()
{
await Task.Delay(1).ConfigureAwait(false);
DoCpuBoundWork();
await Bar();
}
将按预期工作(一切都在线程池上执行,除了button1_Click
的代码)。 但这更糟糕:捕获上下文或不捕获取决于等待实施。
await Task.Delay(0).ConfigureAwait(false);
是一个糟糕的mans Task.Yield()
尝试(这是行不通的,因为我猜如果参数为零,Delay会自行优化)。
我不建议在这里收益。
我认为在你的点击处理程序中你应该推送到线程池:
await Task.Run(async () => await Foo());
这非常简单,如果您调用的方法不依赖于UI的同步上下文,则始终有效。 这在架构上很好,因为您调用的方法不需要或应该知道它们被调用的代码。
Task.Factory.StartNew()可用于在单独的线程中轻松运行代码。 您可以选择通过调用Wait()使当前线程等待第二个线程。
以下是一个快速示例程序,演示了相关部分:
class Program
{
static void Main(string[] args)
{
Task t = Task.Factory.StartNew(() =>
{
//New thread starts here.
LongRunningThread();
});
Console.WriteLine("Thread started");
t.Wait(); //Wait for thread to complete (optional)
Console.WriteLine("Thread complete");
Console.ReadKey();
}
static void LongRunningThread()
{
Console.WriteLine("Doing work");
//do work here
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.