c#中的正确队列线程技术?

时间:2010-09-28 06:20:43

标签: c# windows multithreading windows-services queue

我想实现一个Windows服务,它将丢弃的扁平分隔文件捕获到文件夹以导入数据库。我最初设想的是让FileSystemWatcher查看导入的新文件并创建用于导入的新线程。

我想知道我应该如何正确地实现这个算法以及我应该使用什么技术?我会朝着正确的方向前进吗?

4 个答案:

答案 0 :(得分:1)

我为客户开发了这样的产品。该服务正在监视新文件的多个文件夹,当发现文件时,文件被读取,处理(在条形码打印机上打印),存档和删除。

我们使用“发现者”层,使用FileSystemWatcher发现文件或根据环境进行轮询(因为FileSystemWatcher在监视例如samba共享时不可靠),“文件读取器”层和“处理器”层。

“发现者”图层发现文件并将文件名放在“文件阅读器”图层处理的列表中。 “发现者”层通过设置“文件读取器”层正在等待的事件来表示有新文件要处理。

“文件阅读器”层然后读取文件(使用重试功能,因为在创建文件的过程完全写入文件之前,您可能会收到新文件的通知)。

在“文件阅读器”层读取文件后,使用ThreadPool.QueueWorkItem创建了一个新的“处理器”线程来处理文件内容。

处理完文件后,原始文件将被复制到存档并从原始位置删除。存档也定期清理,以防止服务器泛滥。存档非常适合进行故障排除。

现在已经在两年多的时间里在许多不同的环境中使用,并且已经证明非常可靠。

答案 1 :(得分:1)

我已经提供了一项服务。我通过一个计时器进行轮询,该计时器的已用事件处理程序充当管理程序,将新文件添加到队列并启动消耗队列的可配置数量的线程。处理完文件后,它会重新启动计时器。

包含事件处理程序的每个线程都会陷阱并报告所有异常。该服务始终在运行,我使用单独的UI应用程序告诉服务启动和停止计时器。这种方法坚如磐石,服务从未在几年的处理过程中崩溃。

答案 2 :(得分:1)

传统方法是创建一组有限的线程(可能只有1个)并让它们观察阻塞队列。 FileSystemWatcher 1 事件处理程序中的代码将在工作线程出列并处理它们时将工作项排入队列。它可能类似于以下内容,它使用.NET 4.0中提供的BlockingCollection类或Reactive Extensions下载的一部分。

注意:为简洁起见,代码简洁明了。你必须自己扩展和强化它。

public class Example
{
  private BlockingCollection<string> m_Queue = new BlockingCollection<string>();

  public Example()
  {
    var thread = new Thread(Process);
    thread.IsBackground = true;
    thread.Start();
  }

  private void FileSystemWatcher_Event(object sender, EventArgs args)
  {
    string file = GetFilePathFromEventArgs(args);
    m_Queue.Add(file);
  }

  private void Process()
  {
    while (true)
    {
      string file = m_Queue.Take();
      // Process the file here.
    }
  }
}

您可以利用TPL中的Task课程来获得更现代和ThreadPool的方法。您将为需要处理的每个文件(或可能批处理它们)启动新任务。我用这种方法看到的唯一问题是,控制同时打开的数据库连接的数量会更难。它绝对不是一个显而易见的事情,它可能毫无顾虑。

1 FileSystemWatcher已知有点片状,因此通常建议使用辅助方法来发现文件更改,以防{}错过{ {1}}。您的里程可能会因此问题而有所不同。

答案 3 :(得分:0)

为每封邮件创建一个帖子很可能太贵了。如果您可以使用.NET 4,则可以为每条消息启动Task。这将在线程池线程上运行代码,从而减少创建线程的开销。

如果.NET 4不是一个选项,你也可以用asynchronous delegates做类似的事情。但是,在这种情况下,代码会变得复杂一些。这也将利用线程池,并为您节省为每条消息创建新线程的开销。