2016-04-28 17 views
0

Imはコードを書き出しようとしています。FindAsyncエクステンションでmongodbデッドロックが発生する可能性があります

using (var cursor = await SomeCollection.FindAsync(filter, options)) 
{ 
    while (await cursor.MoveNextAsync()) 
    { 
      var batch = cursor.Current; 
      foreach (var item in batch) 
      { 
       //do something 
      } 
    } 
} 

私は拡張子を思い付いた: すべてのFindAsyncに私たちが書くために必要なコードのこの作品があります。私のコード:

public static async Task<List<T>> GetResultsFromFindAsync<T>(this Task<IAsyncCursor<T>> find) 
{ 
    List<T> result = new List<T>(); 
    using (var cursor = await find) 
    { 
     while (await cursor.MoveNextAsync()) 
     { 
      var batch = cursor.Current; 
      foreach (var item in batch) 
      { 
       result.Add(item); 
      } 
     } 
    } 

    return result; 
} 

、今、私が唯一の使用:

List<MyObject> lst = await SomeCollection.FindAsync(filter, options).GetResultsFromFindAsync(); 

質問です:単一Await caluseとプロセスに関与する2つの非同期タスクがあるので、それがデッドロックを引き起こす可能性があります。 私はプロセスに本当に2つのAwait calusesが含まれていることを知っていますが、お互いに葛藤したり、データの損失を引き起こしたりすることはありませんか?

このエクステンションを使用してFindAsyncを実行し、データを取得しました。そのため、テストではデッドロックが発生する可能性があります。

私は非常に理由や理由を知りたいと思います。おかげさまで

答えて

2

デッドロックが発生する可能性がありますか?はい、しかしあなたがリストアップした理由ではありません。誰かがあなたの同期メソッドを呼び出すことを決定し、返さTaskWaitまたはResultを使用している場合

、彼らはデッドロックを得ることができます。そのまさにその理由のために、「なぜ私の仕事は決して完了しないのですか」の質問にはさまれています。 GetResultsFromFindAsyncの中には、Taskが待ち受けているので、ConfigureAwait(false)を使用してください。

これは、GetResultsFromFindAsyncが常に非同期で消費される場合は問題ではないということです。

「単一のawait句」しか存在しません。実際はそうではありません。 はGetResultsFromFindAsyncの実装内でFindAsyncによって返され、その完了と例外(存在する場合)を伝播します。あなたは

SomeCollection.FindAsync(filter, options).GetResultsFromFindAsync()

を呼び出す際には、両方のTasks(インナーTaskとしては、外Taskで待って)待っている効果です。 FindAsyncが(非同期に)スローされた場合、GetResultsFromFindAsyncによって返されたTaskは自動的にFaulted州に移行し、外側はTaskが待たれているときに例外が再スローされます。

結論として、ConfigureAwait(false)を導入しても傷つきませんが、結論として、あなたが書いた方法には技術的に問題はありません。 FindAsyncを呼び出すとGetResultsFromFindAsyncの責任であるように、

EDITは

上記のすべてを言って、私は個人的には、1に2つのコールをマージ検討します。これは、私は次のように失敗する期待どおりFindAsyncによって返されたカーソルを再利用から消費者を防ぐためのものです:

IAsyncCursor<T> cursor = await SomeCollection.FindAsync(filter, options); 
List<MyObject> lst1 = await cursor.GetResultsFromFindAsync(); 
List<MyObject> lst2 = await cursor.GetResultsFromFindAsync(); // BOOM. 
+0

のawaitなく.Resultまたは.WAITを使用してすべての私の前のコール。私はそれらが発生するデッドロック効果について知っています。したがって、「非デッドロック」コードとしてまとめてください。同意する? –

+0

@OriRefael、yep、それはそれを要約します。内部タスクが完了する前に外部タスクが大量の作業を進めることができないため、ここでは「データ損失」の問題もありません。 –

関連する問題