2017-05-18 4 views
1

コードの途中にあるように、ファイルをダウンロードするのを待つ醜いスレッドブロックコードがあり、コマンドラインで進捗レポートを有効にしています。つまり、まだThread.Sleep()よりもいいですか、忙しく待っていますか?とにかく、私はWait/Pulseについて知っていますが、ここでそれをどのように適用するのか分かりません。進捗レポート付きのDownloadFileAsync()を待機中にメインスレッドを一時停止

私のコードを完全にリファクタリングして、その単一の非同期操作を最もクリーンなソリューションに合わせることができますか? WebClientクラスの何かをオーバーライドしてWait/Pulseタイプの待機を利用できますか?

プロジェクトと問題になっている機能:Github

関連スニペット:

static void GetPatch(KeyValuePair<string, string> entry, string part) 
{ 
    string url = entry.Key, 
     fname = url.Substring(url.LastIndexOf("/", StringComparison.Ordinal) + 1), 
     path = G.patchPath + "\\" + fname; 
     bool exists = File.Exists(path); 
    Console.Write(fname + " ... "); 
    string message = "local"; 
    if ((exists && GetSHA1(path) != entry.Value) || !exists) 
    { 
     if (exists) File.Delete(path); 
     G.wc.DownloadProgressChanged += Wc_DownloadProgressChanged; 
     G.wc.DownloadFileAsync(new Uri(url), part); 
     while (G.wc.IsBusy) 
     { 
      // There must be a better way 
      new System.Threading.ManualResetEvent(false).WaitOne(200); 
     } 
     G.wc.DownloadProgressChanged -= Wc_DownloadProgressChanged; 
     message = "done"; 
    } 
    if (File.Exists(part)) File.Move(part, path); 
    G.patchFNames.Enqueue(fname); 
    Green(message); 
} 

private static void Wc_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e) 
{ 
    int p = e.ProgressPercentage; 
    p = p < 100 ? p : 99; 
    Console.Write("{0:00}%\b\b\b", p); 
} 

私と一緒にご負担願いますが、これは私がC#で書かれていると私は絶対だ私の非常に最初のプロジェクトでありますOOPとC#の初心者。

+0

あなたは間違いなくコードと明快さに取り組む必要がありますが、一般的に私はあなたが正しい方法でいると思います。 2つの非同期プロセスが必要です.1つはファイルのダウンロード用で、もう1つは進行状況の監視用です。 2番目のプロセスは、UIをブロックしないように非同期でなければならず、ディスパッチャを使用してUIを更新する必要があります。 – Andrei

+0

あなたはそれを探していますか? https://alexfeinberg.wordpress.com/2014/09/14/how-to-use-net-webclient-synchronously-and-still-receive-progress-updates/ – MistyK

+0

async \ awaitに移動するのはどうですか?待つことができる 'DownloadFileTaskAsync'があり、それはこのコードの大部分の醜さを捨て去ります。 – Evk

答えて

2

私のコメント内のURLからコードをコピーしてみましょう:

public void DownloadFile(Uri uri, string desintaion) 
{ 
    using(var wc = new WebClient()) 
    { 
    wc.DownloadProgressChanged += HandleDownloadProgress; 
    wc.DownloadFileCOmpleted += HandleDownloadComplete; 

    var syncObj = new Object(); 
    lock(syncObject) 
    { 
     wc.DownloadFileAsync(sourceUri, destination, syncObject); 
     //This would block the thread until download completes 
     Monitor.Wait(syncObject); 
    } 
    } 

    //Do more stuff after download was complete 
} 

public void HandleDownloadComplete(object sender, AsyncCompletedEventArgs args) 
{ 
    lock(e.UserState) 
    { 
     //releases blocked thread 
     Monitor.Pulse(e.UserState); 
    } 
} 


public void HandleDownloadProgress(object sender, DownloadProgressChangedEventArgs args) 
{ 
    //Process progress updates here 
} 
+0

はい、完璧です。 userTokenのオーバーロードが鍵になることはわかっていましたが、悲しいことにMSDNはあまり説明的ではなく、例がありません。 – user1263513

0

あなたのハイレベルのコードは、あなたの監視タスクは、すべてのNミリダウンロードの進捗状況をチェックしなければならない。この

public async Task StartFileDownload() 
{ 
    var downloadTask = StartDownload(); 
    var monitoringTask = StartMonitoringProgress(); 

    await Task.WhenAll(downloadTask, monitoringTask); 
} 

のようになります。進行状況バーを更新します。あなたはUIプロセスに参加していないので、直接操作することはできませんが、UIアップデートを「ディスパッチ」する必要があります。

+1

実際に彼が[イベントベースの非同期パターン(EAP)](https:// msdn)を使用する 'DownloadFileAsync() 'を使用しているときに、' DownloadFileTaskAsync() 'を使って' Task'を返していることをあなたのコードは示唆しています。 microsoft.com/en-us/library/wewwczdw(v=vs.110).aspx)。 – Cameron

関連する問題