如何知道我的所有制片人 - 消费者工作何时完成

时间:2014-09-10 15:25:20

标签: c# .net multithreading producer-consumer

我有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;
        }
    }
}

现在,当这个搜索正在进行中时,我的UI被锁定以防止不必要的点击,我想知道我的所有文件夹何时完成搜索以解锁。 但我的问题是因为我搜索了几个文件夹,事件AllFilesProcessedEventHandler()多次被激活,我想知道我的所有搜索完成的时间。

1 个答案:

答案 0 :(得分: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(),阻止集合将在添加所有元素时自动发出信号给Parallel ForEach。

要扫描256GB SSD,剩余74GB,总共738k +文件需要16.8秒。