使用Async / Await重写我的Utils库的正确方法

时间:2013-12-09 16:32:13

标签: c# asynchronous async-await

我有许多我用于许多不同项目的Utils类,其中大多数是静态的,并且是静态方法,通常甚至不会互相调用。

我的目的是利用新的async / await功能但不重写所有内容,所以我的问题是:我可以为Task.Run(()=>添加一个名为MethodAsync的现有方法的新方法吗?方法名)?

示例:

//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绑定方法,它甚至可以在另一个线程中运行。

如果我正确理解,每个异步方法都按定义包含等待一个等待的对象,这是一个Task或另一个异步方法。

这意味着每当我可以使用异步.NET方法时,我都应该等待它并将我的调用方法标记为异步。

但是,应该使用Task.Run调用调用其他所有不调用任何异步方法但可能需要一些时间才能完成的方法。

正确?

修改

所以我已经阅读了所有发布的链接,msdn上的最佳实践和一些博客文章,但在使用新的async / await功能进行编码时,我仍需要完整的例行程序。 这是我到目前为止所得到的:

1)每个具有异步备选方案的.NET方法都应使用异步备用方法。 (据我所知,.NET async方法仅适用于可以异步的方法。)

2)每个使用异步方法的方法也应该是异步的。

3)每个不使用异步方法的方法(因为没有可用)但仍然需要一些cpu-time来执行应该通过使用Task.Run包装它们来实现异步(我知道在这种情况下它应该如果他们想要使用Task.Run的客户端,但由于我只为执行时间超过50ms的方法添加这些包装器,并且仍然可以使用该方法的非异步版本,我仍然不明白为什么我不应该将此包装器放在库中。)

4)每个采用非cpu-time的方法都会导致它等待其他来源(如互联网,数据库,事件等......)应该使用TaskFactory.FromAsync或TaskCompletionSource。

5)现在不推荐使用System.Threading.Tasks.Parallel.Invoke(method1,method2等)。从我读到的内容,如果CLR认为需要并发,Task.Run已经运行并发线程。因此,似乎Task.Run在需要时已经使用了Parallel.Invoke。

2 个答案:

答案 0 :(得分:6)

我终于找到了能够消除我所有怀疑的好资源:

第一个是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,而不是等待该操作结束,从而提高响应能力。

答案 1 :(得分:5)

这已经在Should I expose asynchronous wrappers for synchronous methods?中进行了讨论。本文中我想强调为什么这是一个糟糕的设计如下:

  

例如,考虑像Dictionary<TKey,TValue>.Add(TKey,TValue)这样的简单方法。这是一种非常快速的方法,对吧?通常,是的,但请记住字典是如何工作的:它需要对密钥进行散列以便找到正确的存储桶,并且需要检查密钥与存储桶中已有的其他条目的相等性。那些散列和相等性检查可以导致对用户代码的调用,以及谁知道这些操作做了什么或者花了多长时间。字典上的每个方法都应该暴露异步包装吗?这显然是一个极端的例子,但有更简单的例子,如Regex。提供给Regex的正则表达式模式的复杂性以及输入字符串的性质和大小会对与Regex匹配的运行时间产生重大影响,以至于Regex现在支持可选的超时......如果Regex上的每个方法都有异步等价?我真的希望不会。

显然我建议你阅读整篇文章,但我希望上面强调了为什么暴露*Async()方法不应该在库中包含同步文件的一个很好的理由。

我希望这会有所帮助。