【问题标题】:Multithreading design-pattern多线程设计模式
【发布时间】:2013-06-25 14:12:02
【问题描述】:

同时牢记:

  • 我正在使用一个阻塞队列,它会一直等待直到向其中添加某些内容
  • 我可能会收到两次 FileSystemWatcher 事件

更新代码:

 {
        FileProcessingManager processingManager = new FileProcessingManager();
        processingManager.RegisterProcessor(new ExcelFileProcessor());
        processingManager.RegisterProcessor(new PdfFileProcessor());
        processingManager.Completed += new ProcessingCompletedHandler(ProcessingCompletedHandler);
        processingManager.Completed += new ProcessingCompletedHandler(LogFileStatus);
        while (true)
        {
            try
            {
                var jobData = (JobData)fileMonitor.FileQueue.Dequeue();
                if (jobData == null)
                    break;

                _pool.WaitOne();
                Application.Log(String.Format("{0}:{1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), "Thread launched"));
                Task.Factory.StartNew(() => processingManager.Process(jobData));
            }
            catch (Exception e)
            {
                Application.Log(String.Format("{0}:{1}", DateTime.Now.ToString(CultureInfo.InvariantCulture), e.Message));
            }
        }
    }

考虑到两个相同的字符串路径可能被添加到阻塞队列中的可能性,您对使代码多线程有什么建议?我留下了可能发生这种情况的可能性,在这种情况下..文件将被处理两次,问题是有时我得到两次,有时没有,这真的很尴尬,如果您对此有建议,请告诉。

空值检查是为了退出循环,我特意在线程循环外加一个空值来判断它是否停止。

【问题讨论】:

  • 您可以对队列进行重复数据删除吗?你期待什么样的路径?如果您正在处理多个目录中的所有文件,那么您可以为每个目录执行一个线程。
  • 收到警报后,可以先将文件移动到子文件夹吗?如果移动成功,则将其添加到队列中。由于一个文件只能从 A 移动到 B 一次,这应该可以防止重复。
  • 文件路径,在单个目录中,仅此而已。我不知道重复数据删除是否对我有帮助,因为当第二个事件到达时,第一个通知可能会从队列中弹出,因此第二个通知在当时队列中是唯一的
  • @mbeckish 你的想法很有趣,但是考虑到例如非常大的文件,这不会增加很多开销吗?
  • @A.K - 你可以做一些其他的原子操作,比如向数据库表中添加一条记录,创建一个空的“锁定”文件,等等。

标签: c# multithreading design-patterns


【解决方案1】:

对于多线程...我可能会在您的 FileProcessingManager 中添加一个“已完成”事件并注册它。该事件的一个参数将是您当前拥有的“布尔”返回值。然后在那个事件处理程序中,我会检查布尔值并重新排队文件。请注意,您必须保留对 FileMonitorManager 的引用。因此,我将把这个 ThreadProc 方法放在一个类中,您可以在其中将 FileMonitorManager 和 FileProcessingManager 实例保存在一个属性中。

为了去重,在 ThreadProc 中,我会在 while 循环之外创建一个列表。然后在while循环中,在处理文件之前,锁定该列表,检查字符串是否已经在其中,如果没有,将字符串添加到列表并处理文件,如果是,则跳过处理。

显然,这是基于围绕您的方法的少量信息,但无论如何都是我的 2 美分。

粗略的代码,来自记事本:

private static FileMonitorManager fileMon = null;
private static FileProcessingManager processingManager = new FileProcessingManager();

private static void ThreadProc(object param)
{
    processingManager.RegisterProcessor(new ExcelFileProcessor());
    processingManager.RegisterProcessor(new PdfFileProcessor());
    processingManager.Completed += ProcessingCompletedHandler;
    var procList = new List<string>();

    while (true)
    {
        try
        {
            var path = (string)fileMon.FileQueue.Dequeue();
            if (path == null)
                break;

            bool processThis = false;
            lock(procList)
            {
                if(!procList.Contains(path))
                {
                    processThis = true;
                    procList.Add(path);
                }
            }
            if(processThis)
            {
                Thread t = new Thread (new ParameterizedThreadStart(processingManager.Process));
                t.Start (path);
            }
        }
        catch (System.Exception e)
        {
            Console.WriteLine(e.Message);
        }
    }
}

private static void ProcessingCompletedHandler(bool status, string path)
{
    if (!status)
    {
        fileMon.FileQueue.Enqueue(path);
        Console.WriteLine("\n\nError on file: " + path);
    }
    else
        Console.WriteLine("\n\nSucces on file: " + path);
}

【讨论】:

  • 另一个问题,我是 c# 中的事件的新手,实际上是 c# 的新手,只是阅读它们,不应该在某处调用 ProcessingCompletedHandler 吗?对不起,如果我弄错了。
  • 据我了解,这个事件处理只是让你从你的类中调用一个在你的类之外定义的函数。所以必须有一个函数调用。
  • 您可以通过 C# 中的委托来执行该事件。 Here 是一篇解释委托的文章,从简单到复杂的用例。在您的情况下,您将在 FileProcessingManager 中定义一个委托和一个事件。然后在它的 Process 方法中,您将引发事件。请参阅该链接中标题“多播”和“事件”下的示例。
  • Tombala 的建议指出了代码的中心部分如何跟踪当前处理的文件的方向。我会研究任务并行技术,一般是任务类。
  • 使用 TPL 限制线程池大小似乎有点棘手。 See this
猜你喜欢
  • 2013-06-20
  • 2020-12-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多