2017-08-04 9 views
2

私は100K +ファイルをダウンロードしており、一度に100ファイルなどのパッチでそれを実行します。 は、次の100をダウンロードし、その後、一度に100個のファイルをダウンロードすることを期待して期待forループでx回ずつ非同期で実行します。

static void Main(string[] args) { 
    Task.WaitAll(
     new Task[]{ 
      RunAsync() 
    }); 
} 

// each group has 100 attachments. 
static async Task RunAsync() { 
    foreach (var group in groups) { 
     var tasks = new List<Task>(); 
     foreach (var attachment in group.attachments) { 
      tasks.Add(DownloadFileAsync(attachment, downloadPath)); 
     } 
     await Task.WhenAll(tasks); 
    } 
} 

static async Task DownloadFileAsync(Attachment attachment, string path) { 
    using (var client = new HttpClient()) { 
     using (var fileStream = File.Create(path + attachment.FileName)) { 
      var downloadedFileStream = await client.GetStreamAsync(attachment.url); 
      await downloadedFileStream.CopyToAsync(fileStream); 
     } 
    } 
} 

実際の 同時に多くのダウンロードを行います。すぐにエラーが発生するUnable to read data from the transport connection: An existing connection was forcibly closed by the remote host

+2

に例外処理を追加することを忘れないでください。クエンティンが使うものは失敗します。 – Bartosz

+2

私は同意します。重複ではありません。私の推測では、HttpClientメソッドはあなたが望むよりも早く復帰するでしょう。 – BradleyDotNET

+2

[Asynchronous HttpClientは.Net 4.5から集中型負荷アプリケーションに悪い選択ですか?](https://stackoverflow.com/questions/16194054/is-async-httpclient-from-net-4-5-a)大量の負荷を必要とするアプリケーション) –

答えて

4

「バッチ」でタスクを実行することは、パフォーマンスの点ではお勧めできません。長い間実行されていたタスクはバッチ全体をブロックします。より良いアプローチは、完了するとすぐに新しいタスクを開始することです。

@MertAkcakayaが提案するように、これをキューで実装することができます。 DownloadParallelは、すぐにそれが最後のダウンロードを開始して返されます。しかし、私は私の他の答えHave a set of Tasks with only X running at a time

int maxTread = 3; 
System.Net.ServicePointManager.DefaultConnectionLimit = 50; //Set this once to a max value in your app 

var urls = new Tuple<string, string>[] { 
    Tuple.Create("http://cnn.com","temp/cnn1.htm"), 
    Tuple.Create("http://cnn.com","temp/cnn2.htm"), 
    Tuple.Create("http://bbc.com","temp/bbc1.htm"), 
    Tuple.Create("http://bbc.com","temp/bbc2.htm"), 
    Tuple.Create("http://stackoverflow.com","temp/stackoverflow.htm"), 
    Tuple.Create("http://google.com","temp/google1.htm"), 
    Tuple.Create("http://google.com","temp/google2.htm"), 
}; 
DownloadParallel(urls, maxTread); 

async Task DownloadParallel(IEnumerable<Tuple<string,string>> urls, int maxThreads) 
{ 
    SemaphoreSlim maxThread = new SemaphoreSlim(maxThreads); 
    var client = new HttpClient(); 

    foreach(var url in urls) 
    { 
     await maxThread.WaitAsync(); 
     DownloadFile(client, url.Item1, url.Item2) 
        .ContinueWith((task) => maxThread.Release()); 
    } 
} 


async Task DownloadFile(HttpClient client, string url, string fileName) 
{ 
    var stream = await client.GetStreamAsync(url); 
    using (var fileStream = File.Create(fileName)) 
    { 
     await stream.CopyToAsync(fileStream); 
    } 
} 

PSに基づいて別の代替を掲載します。だからを待つのはです。あなたが本当にそれを待つ場合は、メソッドの最後にfor (int i = 0; i < maxThreads; i++) await maxThread.WaitAsync();を追加する必要があります。

PS2:他の質問が大幅に異なる方法を使用しない理由を私は学ぶために喜んでいるだろうとそれは、重複としてマークされてしまった残念だDownloadFile

関連する問題