0

我有以下多線程代碼摘錄,我一直在努力比較壓縮副本和解壓縮後的文件。 應用程序正在壓縮包含可變數量的各種大小文件的文件夾,將文件複製到服務器並解壓縮它們。然後比較這些文件,並將此比較結果輸出到ThreadPool使用CountdownEvent和ManualResetEvent控制ThreadPool中的線程

這裏是目前全法

public void FolderMoverLogic(string folderPathToZip, string unzipOutputDir) 
{ 
    string folderRootDir = Path.GetDirectoryName(folderPathToZip); 
    string folderNameToZip = Path.GetFileName(folderPathToZip); 

    try 
    { 
     //Zips files in <folderPathToZip> into folder <zippedLocal> 
     TransferMethods.CreateZipExternal(folderPathToZip, zippedlocal); 
     //Copies zipped folder to server location 
     File.Copy(zippedlocal + "\\" + folderNameToZip + ".zip", zippedserver + "\\" + folderNameToZip + ".zip"); 
     //Unzips files to final server directory 
     TransferMethods.UnZip(zippedserver + "\\" + folderNameToZip + ".zip", unzipOutputDir + "\\" + folderNameToZip, sizeof(Int32)); 

     TransferMethods m = new TransferMethods(); 

     //Enumerate Files for MD5 Hash Comparison 
     var files = from file in Directory.EnumerateFiles(folderPathToZip, "*", SearchOption.AllDirectories) 
        select new 
        { 
         File = file, 
        }; 

     int fileCount = 0; 
     CountdownEvent countdown = new CountdownEvent(10000); 
     using (ManualResetEvent resetEvent = new ManualResetEvent(false)) 
     { 
      foreach (var f in files) 
      { 
       Interlocked.Increment(ref fileCount); 
       countdown.Reset(fileCount); 
       try 
       { 
        ThreadPool.QueueUserWorkItem(
         new WaitCallback(c => 
          { 
           //Check if any of the hashes have been different and stop all threads for a reattempt 
           if (m.isFolderDifferent) 
           { 
            resetEvent.Set(); 
            CancellationTokenSource cts = new CancellationTokenSource(); 
            cts.Cancel(); // cancels the CancellationTokenSource 
            try 
            { 
             countdown.Wait(cts.Token); 
            } 
            catch (OperationCanceledException) 
            { 
             Console.WriteLine("cde.Wait(preCanceledToken) threw OCE, as expected"); 
            } 
            return; 
           } 
           else 
           { 
            //Sets m.isFolderDifferent to true if any files fail MD5 comparison 
            m.CompareFiles(f.File, folderRootDir, unzipOutputDir); 
           } 
           if (Interlocked.Decrement(ref fileCount) == 0) 
           { 
            resetEvent.Set(); 
           } 
           countdown.Signal(); 
          })); 

       } 
       catch (Exception ex) 
       { 
        Console.WriteLine(ex.ToString()); 
       } 
      } 
      countdown.Wait(); 
      resetEvent.WaitOne(); 
      resetEvent.Close(); 





     } 
    } 
    catch (Exception Ex) 
    { 
     Console.WriteLine(Ex.Message); 
    } 
} 

有用的資源看着迄今:

Is it safe to signal and immediately close a ManualResetEvent?

Stopping all thread in .NET ThreadPool?

MSDN CountdownEvent

線程池的邏輯要求:

  • 對比所有枚舉文件在本地和服務器上的所有線程
  • 返回如果散列不匹配

以前線程池代碼

using (ManualResetEvent resetEvent = new ManualResetEvent(false)) 
{ 
    foreach (var f in files) 
    { 
     testCount++; 
     try 
     { 
      //Thread t = new Thread(() => m.CompareFiles(f.File, unzipped, orglsource)); 
      //t.Start(); 
      //localThreads.Add(t); 
      ThreadPool.QueueUserWorkItem(
       new WaitCallback(c => 
        { 
         if (resetEvent.WaitOne(0)) //Here is the `ObjectDisposedException` 
         { 
          return; 
         } 
         if (!m.Folderdifferent) 
         { 
          m.CompareFiles(f.File, folderRootDir, unzipOutput); 
         } 
         else 
         { 
          resetEvent.Set(); 
         } 
         if (Interlocked.Decrement(ref fileCountZipped) == 0) 
         { 
          resetEvent.Set(); 
         } 

        })); 

     } 
     catch (Exception ex) 
     { 
      Console.WriteLine(ex.ToString()); 
     } 

    } 
    resetEvent.WaitOne(); 
} 

我得到ObjectDisposedExceptions定期與pre顯示的vious代碼。

我的問題是這樣:

  1. 是當前方法的線程安全的嗎?
  2. 是邏輯聲音?
  3. 性能或線程安全的任何改進意見
  4. 是否當前的方法我在上面解決了前面的代碼例外

我一直在測試這個代碼,它一直沒有例外,但我看一些更有經驗的反饋。

+0

你在問錯誤的問題。當你使用線程時,你還沒有檢查你的代碼實際上是否更快。不是這樣。因此,嘗試使這個危險和麻煩的代碼工作是沒有意義的。 – 2013-03-17 00:16:43

+0

@HansPassant如果我正在使用的文件大小大於1 GB,那麼它們可以提供幫助? – jordanhill123 2013-03-17 00:19:10

+0

你不應該問我。你應該*測量*。和不。 – 2013-03-17 00:20:49

回答

3

一些注意事項:

  • 不應該是這個樣子?:
    CountdownEvent countdown = new CountdownEvent(files.Count());
  • 安全嗎? - NO - 我只是不喜歡CountdownEvent的想法,如果任何操作與任何文件失敗,你沒有得到信號和應用程序掛起倒計時。等待(),我更喜歡使用TPL Tasks代替 - 而不是countdown.Wait()和使用Task.WaitAll(tasks)
  • 從不使用線程直接 「的foreach變量」(this thread explains why),所以不是:

    foreach (var f in files) 
    { 
        Task.Run(() => 
        { 
         var whateveryDoWithIt = f.File; 
        } 
    }
    做到這一點:
    foreach (var f in files) 
    { 
        var ftemp = f; 
        Task.Run(() => 
        { 
         var whateveryDoWithIt = ftemp.File; 
        } 
    }

  • 到回答如果它是線程安全的我會回答:是的,如果你修復上面的點,並且所用的所有方法也是線程安全的

+0

是的,它應該是'files.Count()'讓我測試任務庫,看看我得到了什麼。 – jordanhill123 2013-03-17 00:15:58

+0

我將來會使用Tasks庫。我不知道它具有它所具有的所有功能。同樣關於上面的@HansPassant的評論,我以我的當前代碼爲基準進行了測試,並且使用我當前的功能進行了並行化並沒有任何好處。如果我添加的功能比我寫的更簡單,我會實現任務。 – jordanhill123 2013-03-17 00:40:30

相關問題