我有很多用于许多不同项目的 Utils 类,其中大部分是静态的,由通常甚至不会相互调用的静态方法组成。
我的目的是利用新的 async/await 功能,但不重写所有内容,所以我的问题是:我可以为每个名为 MethodAsync 的现有方法添加一个新方法,并使用 Task.Run(() => MethodName )?
例子:
//old code that will not be removed
static void DoSomething()
{ ... }
//new code that will be added
static async Task DoSomethingAsync()
{
//not really sure if Im supposed to use await/async here.
//isn't Task awaitable even without async??
return await Task.Run(() => DoSomething());
}
基本上,在旧代码中,我只有一个普通的同步方法,而在新代码中,我有一个异步方法,如果 CLR 将其视为 CPU 绑定(bind)方法,它甚至可以在另一个线程中运行。
如果我理解正确,每个异步方法根据定义都包含一个等待对象的等待对象,该对象是一个任务或另一个异步方法。
这意味着每当我可以使用异步 .NET 方法时,我都应该等待它并将我的调用方方法标记为异步。
但是,所有其他不调用任何异步方法但可能需要一些时间才能完成的方法都应该使用 Task.Run 调用来调用。
对吗?
编辑
所以我已经阅读了所有已发布的链接、msdn 上的最佳实践和一些博客文章,但在使用新的异步/等待功能进行编码时,我仍然需要遵循完整的例程。 这是我到目前为止得到的:
1) 每个具有异步替代方法的 .NET 方法都应该使用异步替代方法。 (据我所知,.NET 异步方法仅适用于可以异步的方法)。
2) 每个使用异步方法的方法也应该是异步的。
3) 每个不使用异步方法(因为不可用)但仍然需要一些 cpu 时间来执行的方法都应该通过使用 Task.Run 包装它们来异步(我知道在这种情况下它应该如果他们愿意,可以成为使用 Task.Run 的客户端,但由于我只为执行时间超过 50 毫秒的方法添加这些包装器,并且该方法的非异步版本仍然可用,我仍然不明白为什么我不应将此包装器放入库中)。
4) 由于等待其他来源(如互联网、数据库、事件等)而占用非 CPU 时间的每个方法都应使用 TaskFactory.FromAsync 或 TaskCompletionSource。
5) System.Threading.Tasks.Parallel.Invoke(method1, method2, etc...) 现已弃用。根据我的阅读,如果 CLR 认为需要并发,Task.Run 已经运行并发线程。因此,Task.Run 似乎已经在需要时使用了 Parallel.Invoke。
最佳答案
我终于找到了很好的资源,消除了我所有的疑虑:
第一个是“基于任务的异步模式”,位于 http://www.microsoft.com/en-us/download/details.aspx?id=19957。 本文档解释了 async/await 功能,如何/何时使用它,它包含许多实际示例和一些非常有用的静态方法,我现在在每个项目中都在使用它们!
第二个是“异步之禅:最佳性能的最佳实践”,网址为 http://channel9.msdn.com/Events/BUILD/BUILD2011/TOOL-829T。 这是对异步功能的完整概述,涵盖了一些并行功能,还解释了为什么它永远不应该是使用 Task.Run() 方法的库,而应该是消费者的选择。
所以最后我真的把多线程和异步代码混为一谈,我无法理解异步代码的优势,因为我当时只看 1 个单一的方法,而异步代码的真正好处只有在整个项目(或至少它的一致部分)是按照异步模式编写的。 例如在 asp.net 中,如果没有任何阻塞代码(所有内容都以异步方式编写),那么线程可以在您的客户端等待异步操作时为另一个客户端提供服务,从而提高可伸缩性,而在 xaml 应用程序中线程启动异步操作的用户可以立即返回支持您的 UI,而不是等待该操作结束,从而提高响应能力。
关于c# - 使用 Async/Await 重写我的 Utils 库的正确方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20475649/