2016-07-22 62 views
0

我想尋求你的幫助,在我的C#程序中實現多線程。C#多線程 - 上傳到FTP服務器

該程序旨在將10,000 ++文件上傳到FTP服務器。我打算至少實現10個線程來提高進程的速度。

有了這個,這是我的代碼行:

我已經初始化10個線程:

public ThreadStart[] threadstart = new ThreadStart[10]; 
public Thread[] thread = new Thread[10]; 

我的計劃是一個文件分配一個線程,如下所示:

file 1 > thread 1 
file 2 > thread 2 
file 3 > thread 3 
. 
. 
. 
file 10 > thread 10 
file 11 > thread 1 
. 
. 
. 

因此,我有以下幾點:

foreach (string file in files) 
{ 
    loop++; 

    threadstart[loop] = new ThreadStart(() => ftp.uploadToFTP(uploadPath + @"/" + Path.GetFileName(file), file)); 
    thread[loop] = new Thread(threadstart[loop]); 
    thread[loop].Start(); 

    if (loop == 9) 
    { 
     loop = 0; 
    }       
} 

文件傳遞到各自的線程正在工作。我的問題是線程的開始重疊。

異常的一個例子是當線程1正在運行時,然後將文件傳遞給它。它返回一個錯誤,因爲線程1尚未成功完成,然後傳遞給它一個新參數。其他線程也是如此。

實現此目的的最佳方法是什麼?

任何反饋將不勝感激。謝謝! :)

+0

您可以使用TPL,讓'SynchronisationContext'處理您可以創建的線程數量.... –

+0

......或'TaskSchedular' .... –

+1

由於這是一個網絡相關的問題,所以至少應該使用'async/await'來實現IOCP的常規性。比旋轉剛好阻塞網絡操作的線程好得多。你甚至可能想考慮_TPL Dataflow_,至少在你的網絡帶寬變平的時候 – MickyD

回答

1

使用異步的await,只是通過文件的數組進去:

private static async void TestFtpAsync(string userName, string password, string ftpBaseUri, 
     IEnumerable<string> fileNames) 
    { 
     var tasks = new List<Task<byte[]>>(); 
     foreach (var fileInfo in fileNames.Select(fileName => new FileInfo(fileName))) 
     { 
     using (var webClient = new WebClient()) 
     { 
      webClient.Credentials = new NetworkCredential(userName, password); 
      tasks.Add(webClient.UploadFileTaskAsync(ftpBaseUri + fileInfo.Name, fileInfo.FullName)); 
     } 
     } 
     Console.WriteLine("Uploading..."); 
     foreach (var task in tasks) 
     { 
     try 
     { 
      await task; 
      Console.WriteLine("Success"); 
     } 
     catch (Exception ex) 
     { 
      Console.WriteLine(ex.ToString()); 
     } 
     } 
    } 

然後調用它像這樣:

const string userName = "username"; 
    const string password = "password"; 
    const string ftpBaseUri = "ftp://192.168.1.1/"; 
    var fileNames = new[] { @"d:\file0.txt", @"d:\file1.txt", @"d:\file2.txt" }; 
    TestFtpAsync(userName, password, ftpBaseUri, fileNames); 
+0

此解決方案適用於我。謝謝! – kevingerard

0

爲什麼做了艱辛的道路? .net已經有一個名爲ThreadPool的類。 您可以使用它並管理線程本身。 您的代碼將是這樣的:

static void DoSomething(object n) 
    { 
     Console.WriteLine(n); 
     Thread.Sleep(10); 
    } 

    static void Main(string[] args) 
    { 
     ThreadPool.SetMaxThreads(20, 10); 
     for (int x = 0; x < 30; x++) 
     { 
      ThreadPool.QueueUserWorkItem(new WaitCallback(DoSomething), x); 
     } 
     Console.Read(); 
    } 
+1

使用ThreadPool的唯一缺點是,您必須跟蹤所有作業以確定它們何時準備就緒。你可以使用'Parallel.ForEach'來代替它。 –