【问题标题】:Waiting async method inside sync method without blocking the thread在同步方法中等待异步方法而不阻塞线程
【发布时间】:2013-10-22 11:27:11
【问题描述】:

我有一些在 Unity 游戏引擎下​​运行的代码。该代码的一部分也在服务器(IIS 8.0、Azure Cloud)上运行。由于 Unity 仅支持 .Net Framework(3.5 或接近它的版本)的子集,因此目前不支持 async / await 模式。

当然,我的服务器完全是使用异步方法构建的。问题是 Unity 代码需要调用我的一些服务器方法,并且不能使用 await 关键字。我需要为 Unity 代码公开一些基本方法,以便它可以在服务器上调用它们。

例如我可以有以下代码:

   Public bool Save()
   {
       Task.Run(async() => await PlayerService.SavePlayer());
       return true;
   }

这当然运行良好,但我需要确保方法 save 在保存完成之前不会返回。现在我如何等待该任务运行到最后,然后再返回方法 Save()?在不阻塞线程的情况下也这样做?阻止该方法很好。

顺便说一句。 PlayerService.SavePlayer(); 中有大量的等待调用;

还有同步上下文的问题,通过SignalR调用初始调用时似乎不喜欢上下文发生变化。

为了澄清 SignalR 是如何在此处涉及的,这是该模式的一个示例:

SignalR 收到一条消息 -> 这会从内存中加载模型的实例(Unity 代码) -> 然后模型认为现在是保存其状态并调用服务器方法的好时机 -> 调用 Save() 方法-> Save 调用 playerservices 中的异步方法 -> 这很神奇 -> 返回到 save -> 模型看到保存成功并继续执行它的业务。

【问题讨论】:

  • 一个线程不能在没有“阻塞”的情况下“等待”,因为这两个实际上是同义词。除非你想忙着等待,否则while (!task.IsCompleted) { }
  • 或者您可能只想等待某些代码仅在任务完成后才运行?如果是这样,那就看看msdn.microsoft.com/en-us/library/…

标签: c# asynchronous signalr


【解决方案1】:

现在我如何等待该任务运行到最后,然后再返回方法 Save()?

在这种情况下,您可以通过Task.Run 返回的Task Wait。这不是最佳解决方案(这是一个 hack),但除非 Unity 支持 await,否则您无法获得最佳解决方案。

在不阻塞线程的情况下也这样做?

这是不可能的。您正在向 Unity 公开一个同步方法,当一个同步方法返回时,它就完成了。因此,您必须在启动异步操作后阻塞线程或返回(就像您的代码已经在做的那样)。

还有同步上下文的问题,通过SignalR调用初始调用时似乎不喜欢上下文发生变化。

SignalR 1.x 在SynchronizationContext 周围有一些怪癖。 SignalR 2.0 刚刚发布(他们应该在那个版本中修复这些怪癖);我会尝试升级,看看效果是否更好。

【讨论】:

  • 感谢斯蒂芬的回答,我暗暗希望你能回答这个问题:)。在这里阻塞线程并不是一个真正的选择,因为这会降低我服务器的性能。只是可能需要解决问题,以便方法在任务结束之前返回无关紧要。
  • 早退是危险的;提前返回的后果是该操作可能实际上并未完成(例如,您的用户收到一条确认消息,表明他们的玩家已保存,但实际上并未保存 - 或仅保存了中途......)。正确的设计是将保存请求放入队列 (Azure/MSMQ) 并让单独的服务处理这些请求。如果您必须将其全部保存在 ASP.NET 中,那么您可以使用type on my blog最小化后果的可能性,但它们仍然可能发生。
  • 队列是理想的,但它没有这里需要的性能。实际上,手头的任务是将对象保存到 Azure Table,所以我想我很确定数据会被保存。在实际保存到表存储之前,还会发生大量负载平衡和分片。进行保存的类也保留在内存中,直到 IIS 进程结束。即使这样,它仍然会使用关闭超时时间来完成任何未完成的任务。
  • @NextKalle:解决性能问题的正确方法是向外扩展。你 have no guarantees 用于 Azure 表;请注意,SLA 不是服务保证——它只是在服务中断时的付款保证。您无法确定“进行保存的类会保留在内存中,直到 IIS 进程结束”或者它可以“使用关闭超时时间来完成任何未完成的任务”。抱歉,但我坚持使用队列扩展的建议。
  • @Stephen Cleary 我只是想澄清这一点,即阻塞 - 合理地进入睡眠 - 工作线程“并不总是有害的”并且比协程、微线程等具有“一些好处”。一种这样的服务器端案例将是专用于与外部硬件(如硬盘驱动器)通信的线程?如果您想争分夺秒..继续并开始一个问题。我做完。再见。祝你今天过得愉快。 :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-12-04
  • 1970-01-01
  • 2023-03-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-06-09
相关资源
最近更新 更多