在GUI应用程序中,有很多方法可以运行异步代码并使结果在"主"线程上运行:
- 使用
async
/await
- 使用
BackgroundWorker
-
someControl.Invoke()
-
.ContinueWith(..., TaskScheduler.FromCurrentSynchronizationContext())
等等。
但是,这些选项在控制台应用程序中都不起作用,因为没有同步上下文或 GUI 运行循环。
我正在修改一个控制台项目,该项目有自己的手动运行循环。 像这样:
while (!cancelled)
{
if(api.HasMessage())
{
api.HandleMessage();
}
Thread.Sleep(1);
}
我希望能够在这个项目中发出异步 Web 请求,同时仍然在主运行循环线程上处理结果以避免典型的多线程问题。 当然,我可以使用队列手动执行此操作,但是能够使用async
/await
或其他处理得更好的范例之一会很好。
有没有我可以从运行循环中调用的方法来实现这一点? 我在想象类似的东西,比如说,Thread.ResolveCurrentAwaitingTasks()
.
这并不像调用方法那么容易,因为async
延续被调度到SynchronizationContext
或TaskScheduler
,而不是线程。所以,你必须写其中之一 - 不是一个非常有趣的前景。
你可以使用我写的一个名为AsyncContext
的SynchronizationContext
;正常用法是这样的:
AsyncContext.Run(() =>
{
while (!cancelled)
{
if(api.hasMessage())
{
api.handleMessage();
}
Thread.Sleep(1);
}
});
这适用于async
代码:
AsyncContext.Run(async () =>
{
while (!cancelled)
{
if(api.hasMessage())
{
await api.handleMessageAsync();
}
Thread.Sleep(1);
}
});
虽然我必须说Thread.Sleep
有点黑客。我会考虑使用事件或其他类型的消息到达通知,例如 await api.GetNextMessageAsync()
.