在没有消息循环和异步无效的情况下,如何让 运行 线程等待一些单独的回调到 return?
How can i keep running thread awaited for some separate callbacks to return, without message-loop and async void?
假设我们有一个 wpf window,其中有一个名为 button1
的按钮,它处理的 void 与此相同:
void Button1_Clicked()
{
// configuring some new work...
// awating for this work to be completed:
while (!_WorkIsCompleted)
{
System.Windows.Threading.Dispatcher.CurrentDispatcher.Invoke(() => { }, System.Windows.Threading.DispatcherPriority.Background);
}
// prompting user that this works is completed.
}
然后假设这个 UI 场景:
用户单击 button1 和 void Button1_Clicked
调用。所以
ui 线程正在等待完成特定工作。
此时用户再次点击button1,我们开始一个新的工作(而旧的工作仍在运行且未完成)。我们等待再次使用消息循环来完成此操作。
第一部作品完成。但是由于消息循环架构,用户无法收到它的提示。因为调用栈等待后面的工作完成,那么returns.
因此,用户先收到延迟工作的提示,然后收到提前工作的提示。
换句话说,较早的呼叫将等待 return 的下一次呼叫。但是如果我们在 async
void 中使用 await
关键字,我们可以得到预期的真实结果。由于某些体系结构和代码模式问题,我无法在我的项目中使用任务。消息循环无法为我提供真实结果。
我知道当我们使用 await
关键字调用 async
void(或函数)时,它告诉编译器(可能在编译时)对程序员代码进行一些编辑以支持等待操作.
而且似乎在等待期间,Call Stack 可以自由地通过 运行 线程进行更多调用。使用 await
关键字,我们可以让 运行 线程同时等待许多等待的调用,彼此不相关。 (这种行为是我现在想要的。)
实际上 async
void 的编译代码中发生了什么,这使得 await 可以单独进行多次调用,并且不冻结 运行 线程?我一定有可能为我的情况做同样的事情。我如何编辑或更改我的代码以做出相同的行为?在 c# 中有解决方案吗?
Actually what is happening in compiled code of an async void, that makes await possible for multiple calls separately, with non-freezing the running thread?
await
不会 创建嵌套的消息循环。相反,await
将 return(在捕获 "context" 之后)。稍后,当等待的对象完成时,该 async
方法的其余部分将发布到上下文 - 在本例中为 WPF UI 上下文。然后主消息循环获取该消息并执行 async
方法的其余部分。我有一个 async intro 可以更详细地解释这些基本机制。
How can i edit or change my code to make a same behavior?
async
/await
是编译器级别的转换;它不能仅通过代码复制,除非您愿意自己进行所有转换(这会变得混乱,尤其是循环)。
因此,让您的代码像 await
一样工作的最简单方法是...使用 await
.
第一步是用信号替换布尔值 _IsCompleted
。在这种情况下,信号应该是异步消耗的并且只会被触发一次,所以合适的类型是TaskCompletionSource<T>
(对于任何T
):
private readonly TaskCompletionSource<object> _CompletedTcs = new TaskCompletionSource<object>();
不是将 _IsCompleted
设置为 false
,而是设置信号:
// was: _IsCompleted = false;
_CompletedTcs.SetResult(null);
然后您可以 await
结果任务:
// was: while (!_IsCompleted) { ... }
await _CompletedTcs.Task;
假设我们有一个 wpf window,其中有一个名为 button1
的按钮,它处理的 void 与此相同:
void Button1_Clicked()
{
// configuring some new work...
// awating for this work to be completed:
while (!_WorkIsCompleted)
{
System.Windows.Threading.Dispatcher.CurrentDispatcher.Invoke(() => { }, System.Windows.Threading.DispatcherPriority.Background);
}
// prompting user that this works is completed.
}
然后假设这个 UI 场景:
用户单击 button1 和 void
Button1_Clicked
调用。所以 ui 线程正在等待完成特定工作。此时用户再次点击button1,我们开始一个新的工作(而旧的工作仍在运行且未完成)。我们等待再次使用消息循环来完成此操作。
第一部作品完成。但是由于消息循环架构,用户无法收到它的提示。因为调用栈等待后面的工作完成,那么returns.
因此,用户先收到延迟工作的提示,然后收到提前工作的提示。
换句话说,较早的呼叫将等待 return 的下一次呼叫。但是如果我们在 async
void 中使用 await
关键字,我们可以得到预期的真实结果。由于某些体系结构和代码模式问题,我无法在我的项目中使用任务。消息循环无法为我提供真实结果。
我知道当我们使用 await
关键字调用 async
void(或函数)时,它告诉编译器(可能在编译时)对程序员代码进行一些编辑以支持等待操作.
而且似乎在等待期间,Call Stack 可以自由地通过 运行 线程进行更多调用。使用 await
关键字,我们可以让 运行 线程同时等待许多等待的调用,彼此不相关。 (这种行为是我现在想要的。)
实际上 async
void 的编译代码中发生了什么,这使得 await 可以单独进行多次调用,并且不冻结 运行 线程?我一定有可能为我的情况做同样的事情。我如何编辑或更改我的代码以做出相同的行为?在 c# 中有解决方案吗?
Actually what is happening in compiled code of an async void, that makes await possible for multiple calls separately, with non-freezing the running thread?
await
不会 创建嵌套的消息循环。相反,await
将 return(在捕获 "context" 之后)。稍后,当等待的对象完成时,该 async
方法的其余部分将发布到上下文 - 在本例中为 WPF UI 上下文。然后主消息循环获取该消息并执行 async
方法的其余部分。我有一个 async intro 可以更详细地解释这些基本机制。
How can i edit or change my code to make a same behavior?
async
/await
是编译器级别的转换;它不能仅通过代码复制,除非您愿意自己进行所有转换(这会变得混乱,尤其是循环)。
因此,让您的代码像 await
一样工作的最简单方法是...使用 await
.
第一步是用信号替换布尔值 _IsCompleted
。在这种情况下,信号应该是异步消耗的并且只会被触发一次,所以合适的类型是TaskCompletionSource<T>
(对于任何T
):
private readonly TaskCompletionSource<object> _CompletedTcs = new TaskCompletionSource<object>();
不是将 _IsCompleted
设置为 false
,而是设置信号:
// was: _IsCompleted = false;
_CompletedTcs.SetResult(null);
然后您可以 await
结果任务:
// was: while (!_IsCompleted) { ... }
await _CompletedTcs.Task;