异步等待最佳实践

5

我掌握了async/await的概念,也有零散地使用过它,但是还有一些关于最佳实践的问题。

  1. 在一个while(condition)循环中使用await来获取可能存在的数据,直到while条件更改,例如stopProcessingMessages = false,这样做是否可以?

  2. 在winforms等应用程序中,当UI运行在其线程上时,对于如按钮单击之类的操作,使用async/await非常简单。但是如果我想在整个控制台应用程序甚至是Windows服务中强制异步执行,最佳实践是什么?要启动第一个await任务,最好的方式是Task.Run(() => ...)吗?

希望我的第二个问题表达清晰。我想充分利用async并将其应用到最大化,但需要理解如何启动初始异步操作,在它传递给所有其他异步函数之前。对于没有使用正确代码块,我道歉,因为我正在乘坐火车使用我的智能手机。

3个回答

7
我已经掌握了async await的概念并且零散地使用它,但是有几个关于最佳实践的问题。
我有一个介绍async/await的博客文章(link1) ,比大多数介绍更详细,同时也介绍了一些最佳实践。
在while(condition)循环中使用await来获取可能存在的数据直到while条件改变(例如stopProcessingMessages=false),这样做是否可行?
你需要避免紧密的循环。所以"while (condition) GetDataIfPresent();"会消耗大量的CPU。
或者,你可以使用一个async方法,如果stopProcessingMessages为true则返回null(或其他内容)。在这种情况下,你的代码将是"while(true)",而更像TAP(Tasks Asynchronous Pattern)的解决方案是使用CancellationSource而不是标志(flag)。
另外请查看TPL Dataflow;听起来它可能对您的情况有用。
对于控制台应用程序,您可以在顶级任务上Wait。这是通常指南(即await而不是Wait)的可接受例外情况。等待将在控制台应用程序的持续时间内占用一个线程,但这通常不足以需要更复杂的解决方案。如果您确实想为控制台应用程序安装单线程上下文,则可以使用我的AsyncEx库中的AsyncContext.Run
对于 Win32 服务,通常需要 启动自己的线程。您可以使用 Task.Run(如果您想要多线程上下文),或使用 AsyncEx 中的 AsyncContextThread(如果您想要单线程上下文)。

感谢 Stephen 提供简明扼要的答案。我最终选择了 TPL Dataflow 的 BufferBlock。在控制台环境中,我还发现使用 Task.Run(async () => await ....); 来启动初始异步进程也足够了。 - Sash
关于控制台顶级的 async 操作:使用 Task.Run 并不比直接调用一个 async 方法更有优势。你仍然需要等待返回的任务完成后才能退出,因此需要使用 Wait 方法。 - Stephen Cleary

2

早上好,

在你的第一个场景中,我更倾向于使用任务创建选项设置为“LongRunning”的常规任务,而不是使用async/await模式。这样,整个while块将在一个长时间运行的任务中执行。在每个while循环内部使用await会启动一个新任务 - 这样做是可行的,但可能不是最优的;-)

关于你的第二个问题,很抱歉,我不明白你的意思。

希望这可以帮助你。


实际上,一个充满await的循环会启动多少个新任务?除非stopProcessingMessages变量迅速设置,否则它有可能会启动成千上万个线程。话虽如此,在问题的上下文中,“继续获取”到底是什么意思呢?单个任务只有一个结果,而不是要持续获取的数据流。 - Snixtor

0

使用循环来获取可能存在的数据是不可取的。您可以创建一个异步调用,完成后将自动调用回调方法。在这种情况下,“等待”阶段将发生在操作系统机制中,该机制以最佳方式处理正在使用的操作系统的等待阶段。

请参阅此处以进一步研究该主题: http://msdn.microsoft.com/en-us/library/vstudio/hh191443.aspx


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接