- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我理解等待任务的异步将执行返回给调用者,允许它继续直到它需要结果。
在某一点之前,我对由此产生的想法的解释是正确的。看起来好像正在进行某种交错。我希望 Do3() 完成,然后将调用堆栈备份到 Do2()。查看结果。
await this.Go();
哪个调用
async Task Go()
{
await Do1(async () => await Do2("Foo"));
Debug.WriteLine("Completed async work");
}
async Task Do1(Func<Task> doFunc)
{
Debug.WriteLine("Start Do1");
var t = Do2("Bar");
await doFunc();
await t;
}
async Task Do2(string id)
{
Debug.WriteLine("Start Do2: " + id);
await Task.Yield();
await Do3(id);
Debug.WriteLine("End Do2: " + id);
}
async Task Do3(string id)
{
Debug.WriteLine("Start Do3: " + id);
await Task.Yield();
Debug.WriteLine("End Do3: " + id); // I did not expect Do2 to execute here once the method call for Do3() ended
}
预期结果:
// Start Do1
// Start Do2: Bar
// Start Do2: Foo
// Start Do3: Bar
// Start Do3: Foo
// End Do3: Bar
// End Do2: Bar
// End Do3: Foo
// End Do2: Foo
//Completed async work
实际输出:
//Start Do1
//Start Do2: Bar
//Start Do2: Foo
//Start Do3: Bar
//Start Do3: Foo
//End Do3: Bar
//End Do3: Foo
//End Do2: Bar
//End Do2: Foo
//Completed async work
这里到底发生了什么?
我正在使用 .NET 4.5 和一个简单的 WPF 应用来测试我的代码。
最佳答案
这是一个 WPF 应用程序,所有这些代码都在同一个 UI 线程上执行。代码中的每个 await
延续都是通过 DispatcherSynchronizationContext.Post
安排的,它将一条特殊的 Windows 消息发布到 UI 线程的消息队列。每个延续都按照其消息发布的顺序发生(这是特定于实现的,您不应该依赖它,但这就是它在这里的工作方式)。
因此,End Do3: Foo
的延续确实是在 End Do3: Bar
的延续之后发布的。输出是正确的。
现在,更详细一些。当我询问 WinForms 与 WPF 时,我希望您的“预期”输出与实际输出相匹配。我刚刚在 WinForms 下测试过,它确实匹配:
// Start Do1
// Start Do2: Bar
// Start Do2: Foo
// Start Do3: Bar
// Start Do3: Foo
// End Do3: Bar
// End Do2: Bar
// End Do3: Foo
// End Do2: Foo
//Completed async work
那么,为什么 WPF 和 WinForms 之间存在差异,虽然两者都运行消息循环,而我们在这里只处理单线程代码?答案可以在这里找到:
Why a unique synchronization context for each Dispatcher.BeginInvoke callback?
WPF 的 DispatcherSynchronizationContext.Post
只是调用 Dispatcher.BeginInvoke
,WPF 的一个重要实现细节是每个 Dispatcher.BeginInvoke
回调都在它自己独特的同步上下文,如链接问题中所述。
这会影响 Task
对象的 await
延续(如 await doFunc()
)。在 WinForms 中,此类延续是内联的(同步执行),因为 SynchronizationContext.Current
保持不变。在 WPF 中,它们不是内联的,而是通过 SynchronizationContext.Post
发布的,因为 SynchronizationContext.Current
before await task
和 task
完成后是不一样的(它在 task.GetAwaiter().OnCompleted
内部由 await
运行时基础结构代码进行比较).
因此,在 WPF 中,它通常是同一个 UI 线程,但与该线程相关联的同步上下文不同,因此延续可能会引发一个异步的 PostMessage
回调,由消息循环。除了 YieldAwaitable
(由 Task.Yield
返回)之外,对于从 WPF UI 触发的 TaskCompletionSource.SetResult
样式延续,您还会遇到这种行为线。
这是相当复杂但特定于实现的东西。如果你想精确控制异步 await
延续的顺序,你可能想推出你自己的同步上下文,类似于 Stephen Toub 的 AsyncPump
。 .尽管通常您不需要它,尤其是对于 UI 线程。
关于c# - 退出异步方法可以将控制权交还给不同的异步方法吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23785227/
所以我使用 PyGame 制作了 Pong,我想使用遗传算法让 AI 学习玩这个游戏。我希望它只知道其桨、球和控件的位置。我只是不知道如何让人工智能自己移动桨。我不想这样做:“如果球在你上方,就向上。
我有包含 4 个子选项卡的 TabControl。 每个选项卡都包含图片框控件。 我需要获取选中的Tab控件的图片框控件。 知道如何实现吗? 最佳答案 也许 var picBox = TabContr
我需要使用 Java 代码控制 Windows XP 的 Windows,我需要单击/键入 windowsXP 给定窗口的特定按钮/文本字段,如何做到这一点有什么想法吗? 我尝试过的方法是:(1) 我
我是一名优秀的程序员,十分优秀!