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つの実装があり、それぞれのパフォーマンスが異なります。1つは非同期で実行し、スレッドをブロックしない(SomeConcreteProvider2)、もう1つは同期して実行できるようにし、タスクオブジェクトを作成しないようにします。など(上記のコードではコーディングできません。つまり、ここで新しいタスクを作成します!)。

非同期Task<T>メソッドを同期的に実行するにはどうすればよいですか?。ただし、何かを同期して実行したくない...コード時(つまり実行前)に、一部のメソッド実装が実際には非同期ではなく、スレッドを使用する必要がないことがわかっている場合は、オーバーヘッドを回避したい/ I / O完了ポートなど。上記のコードを確認すると、SomeConcreteProvider1のメソッドが基本的に文字列(html)を構築し、同じ実行スレッドで非常に迅速に実行できることが簡単にわかります。ただし、SomeConcreteProvider2の同じメソッドでは、Webリクエストを作成し、Webレスポンスを取得して処理する必要があります。リクエスト時にスレッド全体がブロックされないように、少なくともAsyncで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を使用できます

Taskこれにより、並行性を必要とせずにが返されます。

また、コンシューマーコードでは、がすでに完了しているawait場合は譲歩しません。Taskこれは「高速パス」と呼ばれ、メソッドを効果的に同期させます。

于 2012-05-13T14:12:48.447 に答える