是否可以在控制台应用程序的“主”线程上运行异步回调?

Blu*_*eft 4 c# multithreading console-application task-parallel-library async-await

在 GUI 应用程序中,有很多方法可以运行异步代码并在“主”线程上运行结果:

  • 使用async/await
  • 用一个 BackgroundWorker
  • someControl.Invoke()
  • .ContinueWith(..., TaskScheduler.FromCurrentSynchronizationContext())

等等等等

但是,这些选项都不适用于控制台应用程序,因为没有同步上下文或 GUI 运行循环。

我正在修改一个控制台项目,它有自己的手动运行循环。像这样的东西:

while (!cancelled)
{
    if(api.HasMessage())
    {
        api.HandleMessage();
    }
    Thread.Sleep(1);
}
Run Code Online (Sandbox Code Playgroud)

我希望能够在这个项目中进行异步 web 请求,同时仍然在主运行循环线程上处理结果以避免典型的多线程问题。当然,我可以使用队列手动执行此操作,但是能够使用async/await或其他可以更好地处理此问题的范例之一会很好。

有没有我可以从运行循环调用的方法来实现这一点?我在想象这样的事情,比如说,Thread.ResolveCurrentAwaitingTasks()

Ste*_*ary 5

这并不像仅仅调用一个方法那么容易,因为async延续被调度到一个SynchronizationContextor TaskScheduler,而不是一个thread。因此,您必须编写其中之一 - 不是一个非常有趣的前景。

你可以使用SynchronizationContext 我写的一个叫做AsyncContext; 正常使用如下:

AsyncContext.Run(() =>
{
  while (!cancelled)
  {
    if(api.hasMessage())
    {
      api.handleMessage();
    }
    Thread.Sleep(1);
  }
});
Run Code Online (Sandbox Code Playgroud)

这适用于async代码:

AsyncContext.Run(async () =>
{
  while (!cancelled)
  {
    if(api.hasMessage())
    {
      await api.handleMessageAsync();
    }
    Thread.Sleep(1);
  }
});
Run Code Online (Sandbox Code Playgroud)

虽然我必须说这Thread.Sleep有点hackish。我会考虑使用事件或其他类型的消息到达通知,例如await api.GetNextMessageAsync().