2014-09-10 26 views
0

我有Winforms應用程序,閱讀一些網絡文件夾和搜索該文件夾中的文件,這個功能得到List<stirng> folders如何知道什麼時候我所有的生產者 - 消費者作業完成

private decimal _numberOfFiles; 
private static List<string> _folders; 
public delegate void OnFileAddDelegate(List<string> files); 
public event OnFileAddDelegate OnFileAddEventHandler; 
public delegate void OnFinishSearchDelegate(); 
public event OnFinishSearchDelegate OnFinishSearchEventHandler; 

public void SearchFiles() 
{ 
    foreach (string folder in _folders) 
    { 
     if (Directory.Exists(folder)) 
     { 
      var files = Directory.EnumerateFiles(folder, "*.doc", SearchOption.TopDirectoryOnly) 
       .OrderByDescending(x => new FileInfo(x).CreationTime).Take((int)_numberOfFiles).ToList<string>(); 
      if (OnFileAddEventHandler != null) 
       OnFileAddEventHandler(files); 
     } 
    } 

    if (OnFinishSearchEventHandler != null) 
     OnFinishSearchEventHandler(); 
} 

OnFileAddEventHandler(files)事件被激發我ProducerConsumer類開始檢查這List是找到的文件和所做的工作(如果文件被確定解僱了事件到我的主UI添加這個文件到我的ListView):

public class ProducerConsumer 
{ 
    public delegate void OnFileAddDelegate(PcapFileDetails pcapFileDetails); 
    public event OnFileAddDelegate OnFileAddEventHandler; 
    public delegate void AllFilesProcessedDelegate(); 
    public event AllFilesProcessedDelegate AllFilesProcessedEventHandler; 
    private readonly Queue<string> _queue; 
    private int counter; 

    public ProducerConsumer(int workerCount, IEnumerable<string> list) 
    { 
     _isSearchFinished = true; 
     _queue = new Queue<string>(list); // fill the queue 
     counter = _queue.Count; // set up counter 
     for (int i = 0; i < workerCount; i++) 
      Task.Factory.StartNew(Consumer); 
    } 

    private void Consumer() 
    { 
     FileChecker fileChecker = new FileChecker(); 
     for (; ;) 
     { 
      string file; 
      lock (_queue) 
      { 
       // synchronize on the queue 
       if (_queue.Count == 0) return; // we are done 
       file = _queue.Dequeue(); // get file name to process 
      } // release the lock to allow other consumers to access the queue 
      // do the job 
      string result = fileChecker.Check(file); // Check my file 

      if (OnFileAddEventHandler != null && result) // In case my file OK, fired up event to my main UI 
       OnFileAddEventHandler(file); 

      // decrement the counter 
      if (Interlocked.Decrement(ref counter) != 0) 
       continue; // not the last 

      // all done - we were the last 
      if (AllFilesProcessedEventHandler != null) 
       AllFilesProcessedEventHandler(); 
      return; 
     } 
    } 
} 

現在,此搜索正在進行中,我的用戶界面被鎖定以防止不必要的點擊,並且我想知道我的所有文件夾何時完成搜索才能解鎖。 但我的問題是因爲我搜索幾個文件夾事件AllFilesProcessedEventHandler()發射了好幾次,我想知道什麼時候我所有的搜索結束。

+0

你使用哪個版本的.NET? 4.5或更低版本? – 2014-09-10 15:54:52

+0

我正在使用.NET 4.0 – user3637066 2014-09-10 15:55:31

+0

是否有使用隊列的原因?爲什麼不將一個文件夾作爲參數傳遞給該函數,以便您可以避免鎖定?您可以這樣做嗎? – 2014-09-10 16:05:36

回答

0

這裏是QuickIO.Net

using System; 
using System.Collections.Concurrent; 
using System.Threading; 
using System.Threading.Tasks; 
using SchwabenCode.QuickIO; 

namespace ConsoleApplication3 
{ 
    internal class Program 
    { 
     private static readonly BlockingCollection<QuickIOFileInfo> fileInfos = new BlockingCollection<QuickIOFileInfo>(); 
     private static void Main(string[] args) 
     { 
      var task = Task.Factory.StartNew(() => 
      { 
       Int32 totalSize = 0; 
       Parallel.ForEach(fileInfos.GetConsumingEnumerable(), fi => 
       { 
        Interlocked.Add(ref totalSize, (int)fi.Bytes); 
       }); 
       Console.WriteLine("All docs bytes amount to {0}", totalSize); 
      }); 

      ProcessDirectory("C:\\"); 
      fileInfos.CompleteAdding(); 

      Task.WaitAll(task); 
     } 

     private static void ProcessDirectory(string path) 
     { 
      Parallel.ForEach(QuickIODirectory.EnumerateDirectories(path), dir => 
      { 
       try 
       { 
        Parallel.ForEach(QuickIODirectory.EnumerateFiles(dir), file => 
        { 
         if (file.AsFileInfo().Extension.Equals(".docx")) 
          fileInfos.Add(file); 
        }); 
        ProcessDirectory(dir.FullName); 
       } 
       catch (Exception e) 
       { 
        Console.WriteLine("Unable to access directory {0}", dir.FullName); 
       } 
      }); 
     } 
    } 
} 

阻塞收集將自動用信號時的所有元素已經被添加,通過調用CompleteAdding到並行的ForEach()的遞歸樣品。

要掃描一個256GB的SSD,剩下74GB和總共738k +文件花費16.8s。

+0

爲什麼使用'Interlocked.Add'?一個簡單的Map-Reduce看起來更有效率,並且非阻塞。 「Interlocked.Add」的唯一原因是如果你想檢查運行中的計數器。即使這樣,也可以批量處理Map-Reduce(稍微難一些,但是可以)。 – Aron 2014-09-10 17:18:02

+0

確實如此,但樣本決不是生產質量代碼。這只是爲了演示如何在不重新從頭開始重新創建阻塞收集的情況下繼續他的挑戰。 – Darek 2014-09-10 17:33:14

+0

'.AsParallel()。Sum(fi =>(int)fi.Bytes)' – Aron 2014-09-10 17:36:23

相關問題