异步等待错误的执行顺序
本文关键字:执行 顺序 错误 等待 异步 | 更新日期: 2023-09-27 17:56:25
我正在尝试掌握异步等待模式。按照此示例,我实现了这个小程序:
private async void asynchWork()
{
// Line 1
Task<string> readTask = asynchAwaitWork();
// Line 2
synchWork();
// Line 3
string result = await readTask;
// Line 4
Debug.WriteLine(result);
Debug.WriteLine("The End");
}
private void synchWork()
{
for (int i = 0; i < 5; i++)
{
Debug.WriteLine("SynchWork For i : " + i);
Thread.Sleep(750);
}
}
private async Task<string> asynchAwaitWork()
{
for (int i = 0; i < 15; i++)
{
Debug.WriteLine("A-SynchWork For i : " + (i+111));
Thread.Sleep(750);
}
return "finished";
}
我预计第 1 行被执行,然后第 2 行和第 4 行将不得不等到 3 行完成并返回一个字符串。但是查看输出,synchWork
方法在asynchWork
方法之后执行。
A 同步工作 i : 111
A 同步工作 i : 112
A 同步工作 i : 113
A 同步工作 i : 114
A 同步工作 i : 115
。
A 同步工作 i : 125
同步工作 i : 0
同步工作 i : 1
同步工作 i : 2
同步工作 i : 3
同步工作 i : 4
完成
结束
我预计 synchWork
方法将在 asynchWork
方法繁忙并在第 3 行等待结果时执行。我在示例中误解了什么?还是只是 Debug.WriteLine
的输出最终是按顺序执行的,但真正的工作顺序是根据我的期望?
编辑:在评论和答案的帮助下,我学到了:
不要忽视警告并研究它们的含义;)
使用
await
关键字可以等待由方法中创建的Task
执行的操作的结果。
编辑2:
- 但是任务必须开始!否则将没有并行处理,编译器将通过主线程追逐它,并且第 3 行实际上只有第 4 行的阻塞函数,而不是更多。
由于Thread.Sleep(750)
只是一个模拟工作,我真的不需要Delay
这也有效:
private async Task<string> asynchAwaitWork()
{
await Task.Run(()=> {
for (int i = 0; i < 15; i++)
{
Debug.WriteLine("A-SynchWork For i : " + (i+111));
Thread.Sleep(750);
}
});
return "finished";
}
谢谢。我学到了很多:)
只看你的主程序:
当第 3 行执行时,您可以保证在第 1 行中获得的任务已完成执行其中的任何内容。
在第 2 行,您无法保证任务已开始执行或已完成。您不知道它是否会并行运行。您只知道有一个任务可以计划执行。
您在函数asynchAwaitWork
中创建的任务的实现是完全同步的。该实现细节导致它在返回最终(在本例中为立即)返回字符串的 Task 时完全完成打印内容。
请注意,您创建的任务不会打印任何内容。在当前实现中打印"A-SynchWork For i"消息是创建任务的副作用。
只需替换 Thread.Sleep(750);
在 asynchAwaitWork await Task.Delay(750);
问题是 asynchAwaitWork 开始在主线程中工作。异步工作 - 这是为了延续。使用 await 关键字,您可以创建延续,这就是它开始并行工作的原因。此外,将当前线程 ID 添加到输出中,以查看会发生什么。例:
private async void asynchWork()
{
// Line 1
Task<string> readTask = asynchAwaitWork();
// Line 2
synchWork();
// Line 3
string result = await readTask;
// Line 4
Debug.WriteLine(result);
Debug.WriteLine("The End");
}
private void synchWork()
{
for (int i = 0; i < 5; i++)
{
Debug.WriteLine("SynchWork For i : " + i + " and thareadId = " + Thread.CurrentThread.ManagedThreadId);
Thread.Sleep(750);
}
}
private async Task<string> asynchAwaitWork()
{
for (int i = 0; i < 15; i++)
{
Debug.WriteLine("A-SynchWork For i : " + (i + 111) + " and thareadId = " + Thread.CurrentThread.ManagedThreadId);
await Task.Delay(750);
//Thread.Sleep(750);
}
return "finished";
}
如前所述,如果创建了 Task.Delay(750),它将使用相同的同步上下文。例如,如果您从 WPF 运行代码
[STAThread]
void Main()
{
var window = new Window();
window.Loaded += (s, e) => {
asynchWork();
};
window.ShowDialog();
}
您将看到所有内容都发生在同一个线程中。因此,请注意这一点,您可以使用await Task.Delay(750).ConfigureAwait(false);
来避免这种情况。