6

我想使用最近的 C# 5.0 异步方法,但是一些特定的方法。

考虑以下示例代码:

public abstract class SomeBaseProvider : ISomeProvider
{
   public abstract Task<string> Process(SomeParameters parameters);    
}

public class SomeConcreteProvider1 : SomeBaseProvider 
{

   // in this method I want to minimize any overhead to create / run Task
   // NOTE: I remove here async from method signature, because basically I want to run 
   // method to run in sync!
   public override Task<string> Process(SomeParameters parameters) {

      string result = "string which I don't need any async code to get";

      return Task.Run(() => result);
   }
}

public class SomeConcreteProvider2 : SomeBaseProvider 
{

   // in this method, it's OK for me to use async / await 
   public async override Task<string> Process(SomeParameters parameters) {

      var data = await new WebClient().DownloadDataTaskAsync(urlToRequest);

      string result = // ... here we convert data byte[] to string some way

      return result;

   }
}

现在我将如何使用异步方法(在我的情况下,你可以忽略消费者实际上是 ASP.NET MVC4 应用程序......它可以是任何东西):

public class SomeAsyncController : AsyncController
{

    public async Task<ActionResult> SomethingAsync(string providerId)
    {
       // we just get here one of providers I define above
       var provider = SomeService.GetProvider(providerId);

       // we try to execute here Process method in async. 
       // However we might want to actually do it in sync instead, if  
       // provider is actually SomeConcreteProvider1 object.
       string result = await provider.Process(new SomeParameters(...));

       return Content(result);
     }
} 

如您所见,我有 2 个实现,每个实现不同:一个我想异步运行并且不阻塞线程 (SomeConcreteProvider2),而另一个我希望能够同步运行并且不创建任何 Task 对象等(我未能在上面的代码中编码,即我确实在这里创建了新任务!)。

已经有一些问题,例如我将如何同步运行异步 Task<T> 方法?. 但是我不想同步运行某些东西......如果我在代码时(即运行时之前)知道某些方法实现实际上不会是异步的并且不需要使用任何线程,我想避免任何开销/我/O完成端口等。如果您检查上面的代码,很容易看到SomeConcreteProvider1中的方法基本上会构造一些字符串(html),可以在同一个执行线程中非常快速地完成。但是 SomeConcreteProvider2 中的相同方法将需要创建 Web 请求,获取 Web 响应并以某种方式处理它,我确实希望至少在异步中发出 Web 请求以避免在请求期间阻塞整个线程(实际上可能会退出很长时间)。

所以问题是:如何组织我的代码(不同的方法签名或不同的实现,或者?)能够决定如何执行方法并避免任何可能的开销,例如由 SomeConcreteProvider1 中的 Task.Run(...) .工艺方法?

更新1:明显的解决方案(我在提问过程中想到了其中一些),例如向每个提供者添加一些静态属性(比如'isAsyncImplementation'),然后检查该属性以决定如何运行方法(使用等待或在控制器操作中没有等待)也有一些开销:DI 如果可能的话想要更好的东西:D

4

2 回答 2

10

在您的第一种情况下,我建议您返回:

Task.FromResult(result)

它返回一个已完成的任务。

http://msdn.microsoft.com/en-us/library/hh194922%28v=vs.110%29.aspx

于 2012-05-13T14:15:33.580 回答
0

你的设计看起来不错。

对于这种SomeConcreteProvider1情况,您可以使用TaskCompletionSource

这将返回 aTask而不需要并发。

此外,在消费者代码中,如果已经完成,await则不会产生。Task这称为“快速路径”并有效地使方法同步。

于 2012-05-13T14:12:48.447 回答