【发布时间】:2015-01-29 17:55:59
【问题描述】:
我一直在关注this question,并且我理解Peter Duniho 的流行(尽管尚未接受)答案背后的原因。具体来说,我知道 not 等待后续长时间运行的操作会阻塞 UI 线程:
第二个例子在异步操作期间没有产生。相反,通过获取 content.Result 属性的值,可以强制当前线程等待异步操作完成。
为了我自己的利益,我什至已经证实了这一点,就像这样:
private async void button1_Click(object sender, EventArgs e)
{
var value1 = await Task.Run(async () =>
{
await Task.Delay(5000);
return "Hello";
});
//NOTE: this one is not awaited...
var value2 = Task.Run(async () =>
{
await Task.Delay(5000);
return value1.Substring(0, 3);
});
System.Diagnostics.Debug.Print(value2.Result); //thus, UI freezes here after 5000 ms.
}
但现在我想知道:您是否需要 await 嵌套在最外层可等待操作中的所有“等待”操作?例如,我可以这样做:
private async void button1_Click(object sender, EventArgs e)
{
var value0 = await Task.Run(() =>
{
var value1 = new Func<Task<string>>(async () =>
{
await Task.Delay(5000);
return "hello";
}).Invoke();
var value2 = new Func<string, Task<string>>(async (string x) =>
{
await Task.Delay(5000);
return x.Substring(0, 3);
}).Invoke(value1.Result);
return value2;
});
System.Diagnostics.Debug.Print(value0);
}
或者我可以这样做:
private async void button1_Click(object sender, EventArgs e)
{
//This time the lambda is async...
var value0 = await Task.Run(async () =>
{
//we're awaiting here now...
var value1 = await new Func<Task<string>>(async () =>
{
await Task.Delay(5000);
return "hello";
}).Invoke();
//and we're awaiting here now, too...
var value2 = await new Func<string, Task<string>>(async (string x) =>
{
await Task.Delay(5000);
return x.Substring(0, 3);
}).Invoke(value1);
return value2;
});
System.Diagnostics.Debug.Print(value0);
}
而且它们都不会冻结 UI。哪一个更可取?
【问题讨论】:
-
如果它们都打印相同的东西,我会感到非常惊讶,我相信打印的是一个任务对象而不是它的结果。
-
@BenVoigt -- 不,在这两种情况下,任务都被解包,因为它正在等待。
-
但其中一个正在包装第二个任务。
-
@BenVoigt -- 我明白你的意思。这很奇怪。不过,
value0在这两种情况下都是string,但它确实打印了相同的内容。\ -
啊,
Run<TResult>(Func<TResult>)和Run<TResult>(Func<Task<TResult>>)有重载,额外层的展开是在那里进行的。
标签: c# .net asynchronous task-parallel-library async-await