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