2014-03-30 60 views
3

我想用C#並行下載文件。爲此,我編寫了這個工作正常的代碼,但問題在於UI凍結。使用C並行下載多個文件#

using System; 
using System.Collections.Generic; 
using System.IO; 
using System.Linq; 
using System.Net; 
using System.Text; 
using System.Text.RegularExpressions; 
using System.Threading; 
using System.Threading.Tasks; 
using System.Windows; 
using System.Windows.Controls; 
using System.Windows.Data; 
using System.Windows.Documents; 
using System.Windows.Input; 
using System.Windows.Media; 
using System.Windows.Media.Imaging; 
using System.Windows.Navigation; 
using System.Windows.Shapes; 
using System.Windows.Threading; 

namespace FileDownloader 
{ 
    /// <summary> 
    /// Interaction logic for MainWindow.xaml 
    /// </summary> 
    public partial class MainWindow : Window 
    { 
     private static int count = 1; 
     private static string f= "lecture"; 
     private string URL = "www.someexample.com"; 

     public MainWindow() 
     { 
      InitializeComponent(); 
     } 

     public static string GetDirectoryListingRegexForUrl(string url) 
     { 
      if (url.Equals(URL)) 
      { 
       return "<a href=\".*\">(?<name>.*)</a>"; 
      } 
      throw new NotSupportedException(); 
     } 

     public void DownloadP(string[] urls) 
     { 
      Parallel.ForEach(urls.ToList(), new ParallelOptions { MaxDegreeOfParallelism = 10 }, DownloadFile); 
     } 

     private void DownloadFile(string url) 
     { 
      using(WebClient client=new WebClient()) 
      { 
       if (url.EndsWith(".pdf")) 
       { 
        int nextIndex = Interlocked.Increment(ref count); 

        client.DownloadFile(url, f + nextIndex + ".pdf"); 
        this.Dispatcher.Invoke(() => { 
         listbox.Items.Add(url); 
        }); 
       } 
      } 
     } 

     private void Button_Click(object sender, RoutedEventArgs e) 
     { 
      DownloadP(listofFiles); 
     } 
    } 
} 
+1

您應該使用異步,不平行。你沒有任何計算工作。 – SLaks

+0

你希望獲得什麼?這不會受CPU限制。 –

+0

@SLaks&David Heffernan:我在不凍結UI的情況下並行下載文件除外 –

回答

4

您可以使用async/await與新WebClient方法DownloadFileTaskAsync結合。

private async Task DownloadFile(string url) 
{ 
    if (!url.EndsWith(".pdf")) 
    { 
     return; 
    } 

    using (var client = new WebClient()) 
    { 
     int nextIndex = Interlocked.Increment(ref count); 

     await client.DownloadFileTaskAsync(url, "lecture" + nextIndex + ".pdf"); 
     listBox.Items.Add(url); 

    } 
} 

private async void Button_OnClick(object sender, RoutedEventArgs e) 
{ 
    button.IsEnabled = false; 
    await DownloadFiles(urlList); 
    button.IsEnabled = true; 
} 

private async Task DownloadFiles(IEnumerable<string> urlList) 
{ 
    foreach (var url in urlList) 
    { 
     await DownloadFile(url); 
    } 
} 
+0

讓我試試您的代碼 –

+0

爲什麼在這裏使用'Interlocked.Increment'?這段代碼中的所有內容都在相同的UI線程上運行(除了'DownloadFileTaskAsync'內部)。 – Noseratio

+0

@Noseratio這是來自OP的遺留代碼:) –

2

而是採用client.DownloadFile使用client.DownloadFileAsync這樣

var webClient=new WebClient(); 
webClient.DownloadFileCompleted += webClient_DownloadFileCompleted; 
webClient.DownloadFileAsync("Your url","file_name"); 

事件

private void webClient_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e) 
    { 
     MessageBox.Show("Download Completed."); 
    } 
+0

+1好建議 - 請確保使用原始帖子的通知代碼更新您的答案 - 'MessageBox.Show'並不是設計用於並行執行許多操作的代碼的最佳選擇。 –

+0

如何在Parallel.ForEach循環中處理此問題 –

1

與此Relace您DownloadP功能:

public async void DownloadP(string[] urls) 
{ 
    await Task.Factory.StartNew(() => Parallel.ForEach(urls.ToList(), new ParallelOptions { MaxDegreeOfParallelism = 10 }, DownloadFile)); 
}