2017-09-28 20 views
7

ただの質問です。私たちはここでいくつかの誤解をしています。はTask.WhenAll対選択を待っています(async .. =>待っています)

我々が持っている:

var tasks = files.Select(async fileName => await IngestFileAsync(container, fileName)); 
var results = await Task.WhenAll(tasks); 

私は、最初の行がまだ同時行くことを言うが、私の仲間の同僚は、それ以外の場合は言います。また、 のアクションはすべて既に実行されているため、2番目のawaitは意味を持ちません。

は、このコードは同じです:

var tasks = files.Select(fileName => IngestFileAsync(container, fileName)); 
var results = await Task.WhenAll(tasks); 

として:

var tasks = files.Select(async fileName => await IngestFileAsync(container, fileName)); 
var results = Task.WhenAll(tasks); 

誰かがこの上でいくつかの余分な光を当てますか?

歓声。

が追加されました。 okeですので、同時に実行されます。 https://dotnetfiddle.net/lzv2B7 https://dotnetfiddle.net/dMusus

(予告ライン16、asyncawait):

しかし、誰かが差はこれらのコードスニペットの間でどのようないくつかの余分な情報を追加することができます。それら2の間に違いはありますか?

private async Task<Result> IngestFilesAsync(ICloudBlobContainer container, IEnumerable<string> files) 
    { 
     _logger.LogDebug("Start IngestFilesAsync"); 

     var tasks = files.Select(fileName => IngestFileAsync(container, fileName)); 
     var results = await Task.WhenAll(tasks); 

     _logger.LogDebug("All tasks completed"); 

     if (results.Any(t => t.IsFailure)) 
     { 
      return Result.Fail(string.Join(",", results.Select(f => f.Error))); 
     } 

     return Result.Ok(); 
    } 

    private async Task<Result> IngestFileAsync(ICloudBlobContainer container, string fileName) 
    { 
     _logger.LogDebug("Start IngestFileAsync"); 
     var blob = container.GetBlockBlobReference(fileName); 

     _logger.LogDebug("Blob retrieved"); 

     if (await blob.ExistsAsync()) 
     { 
      using (var memoryStream = new MemoryStream()) 
      { 
       _logger.LogDebug("Start download to stream"); 
       await blob.DownloadToStreamAsync(memoryStream); 
       _logger.LogDebug("To mem downloaded"); 

       _logger.LogDebug("Start ftp-upload"); 

       return await _targetFTP.UploadAsync(memoryStream, fileName); 
      } 
     } 

     _logger.LogWarning("Blob does not exists"); 

     return Result.Fail($"Blob '{fileName}' does not exist"); 
    } 
:これは私のコード - ある - 私は期待する何 は非同期で 、それはそれはAwait Task.WhenAll(tasks);

に来るとき、それが開始されることを、直接起動、およびなしでしょう待つがclearityのために追加したことです

ここで、_targetFTP.UploadAsync(memoryStream, fileName);は再びタスクなどです。

+1

両方のケースを 'foreach'ループ(' Select'の代わりに)として書き直してください。 – Fabio

+0

これはテストするのが簡単です:非同期関数 'Task.Delay'を作り、それがどれくらい時間がかかるかを測定します。 – hvd

+0

私のログには@fidorがあります。私は互いに重複した行を見ています。それは、それらが同時に実行されたことを示唆しています。今、私はそれを入力している、それは可能性がありますここに来るかもしれないスレッドがあった。 –

答えて

9

タスクを返すanonymous関数を作成します。そのタスクは、fによって作成されたものを効果的にラップします。それはその後に直ちに完了します。特に、この無名関数は、できるだけ早く進行中のタスクを返します。

.Selectは、列挙型がタスクの1つであるかどうかによって異なる動作をしません。最初に返されたタスクがまだ進行中のときに、次の結果を直接フェッチすることができます。

コードフラグメントは100%同一ではありませんが、お探しの違いはありません。

違いは小さいです。最も目に見える変化はおそらく例外処理です。あなたは2未実装の機能を持っていると仮定します。

ここ
Task Sync() => throw new NotImplementedException(); 
async Task Async() => throw new NotImplementedException(); 

var task = Sync();は明らかにすぐに失敗。しかし、var task = Async();は違う:成功する。ここでasyncというキーワードは、スローされた例外をキャプチャするタスクを強制的に作成します。

この同じ区別は、.Select(x => Sync()).Select(async x => await Sync())にも当てはまります。

+0

ちょうどこのシナリオに言及する価値があります:https://dotnetfiddle.net/rI8U3z – gdoron

+0

oke、それで、それはまだ並行しています。 2番目の 'await' =>' var results = Task.WhenAll(tasks);がまだ意味を持っているか、単にTask.WhenAll(tasks)を使うことができますか? ? –

+0

@RoelantM 'Task.WhenAll(tasks)'はブロックされません。別のタスクが返され、元のタスクがすべて完了したら完了します。ちょうど 'Task.WhenAll(tasks);'は効果がありません。しかし、結果を必要としない場合は ''結果を待たずに '' Task.WhenAll(tasks); 'を待つことができます。 – hvd

関連する問題