我和我的团队支持多个后台工作控制台应用程序,这些应用程序同步处理来自队列的消息。
目前,当队列中的消息数量超过特定阈值时,我们使用 docker 启动应用程序的新实例来处理多条消息。
我们正在讨论并行处理这些消息的替代方法,一位队友建议在 while
循环中使用顶级 async void
方法来处理消息。
看起来它会起作用,因为它类似于使用 async void 作为事件处理程序的基于 UI 的应用程序。
但是,我个人从未编写过后台 worker 以这种方式并行处理多个消息,并且想知道是否有人有这样做的经验,如果有,是否存在我们没有的“陷阱”正在思考。
以下是建议解决方案的简化版本:
static async void Main(string[] args)
{
while (true)
{
TopLevelHandler(await ReceiveMessage());
}
}
static async void TopLevelHandler(object message)
{
await DoAsyncWork(message);
}
static async Task<object> ReceiveMessage()
{
//fetch message from queue
return new object();
}
static async Task DoAsyncWork(object message)
{
//processing here
}
最佳答案
Can I safely use
async void
...
这取决于你所说的“安全”是什么意思。 async void
方法具有特定的行为,因此如果您喜欢这些行为,那么 async void
就可以了。
async void
操作无法等待,因此您不知道它们何时完成。如果您需要在终止程序之前等待所有挂起的异步操作完成,那么async void
不适合您。- 在
async void
操作中引发的未处理异常将在async void
方法启动时捕获的SynchronizationContext
上重新引发。由于您有一个控制台应用程序,因此没有SynchronizationContext
,因此错误将在ThreadPool
上抛出。这意味着您的应用程序将引发 AppDomain.UnhandledException 事件,然后崩溃。如果您要求应用程序不随机崩溃,那么async void
就不适合您。
async void
方法最初是为了使 async
事件处理程序成为可能而发明的。在现代实践中,这仍然是它们的主要用途。
使async void
成为一个有趣选择的一个利基场景是,您有一个工作流程,当它完成时,它必须启动另一个工作流程。如果踢球对于应用程序的连续流程至关重要,并且踢球失败将使您的应用程序处于挂起状态,那么将这种失败升级为进程崩溃事件是有意义的。可以说,崩溃的程序比挂起的程序相对要好。您可以看到针对此场景使用 async void
的两个示例 here和 here 。在第二个示例中,async void
是传递给 ThreadPool.QueueUserWorkItem
方法的 lambda,确保 async void
不会捕获任何未知环境SynchronizationContext
。
关于c# - 我可以在单线程 C# 控制台应用程序中安全地使用 async void 异步处理队列中的多个项目吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73754807/