使用线程队列管理长时间运行的数据处理任务

时间:2011-11-29 12:47:52

标签: c# multithreading

我有一个数据库同步任务需要一些时间来处理,因为在120k叶子记录的区域中,但它们是远程的并且访问相对较慢。

目前,我的应用程序做了一个相当天真的过程

  1. 获取所有本地联系人列表
  2. 对于每个本地联系人,获取所有相关数据
  3. 然后获取匹配的远程联系人
  4. 比较两者并做些事情以使它们同步
  5. 步骤1在数据完成之前返回数据,步骤4不涉及同一组中不同联系人之间的比较。

    我希望做的是使用某种队列构造并在步骤1中开始填充它,然后立即转到步骤2并使用多个线程开始处理项目。

    然后该过程变为:

    1. 开始使用联系人填充队列
    2. 队列中有项目
    3. 启动一个帖子并:
      1. 从队列中取出正面联系人
      2. 获取远程联系人
      3. 比较他们
      4. 执行所需的更新
    4. 我是否正确地假设我可以创建一个新的ConcurrentQueue,开始填充它,然后循环它,因为我可能是一个单线程的简单集合?

      (我没有进行任何错误检查或实际线程,以保持示例简单)

      class Program
      {
          static void Main(string[] args)
          {
              Processor p = new Processor();
              p.Process();
          }
      }
      
      
      class Processor
      {
          bool FetchComplete = false;
          ConcurrentQueue<Contact> q = new ConcurrentQueue<Contact>();
      
          public void Process()
          {
              this.PopulateQueue(); // this will be fired off using QueueUserWorkItem for example
      
              while (FetchComplete == false)
              {
                  if (q.Count > 0)
                  {
                      Contact contact;
                      q.TryDequeue(out contact);
                      ProcessContact(contact); // this will also be in QueueUserWorkItem
                  }
              }
          }
      
      
          // a long running process that fills the queue with Contacts
          private void PopulateQueue()
          {
              this.FetchComplete = false;
              // foreach contact in database
              Contact contact = new Contact(); // contact will come from DB
              this.q.Enqueue(contact);
              // end foreach
      
              this.FetchComplete = true;
          }
      
          private void ProcessContact(Contact contact)
          {
              // do magic with contact
          }
      }
      

1 个答案:

答案 0 :(得分:2)

您最好使用BlockingCollection代替ConcurrentQueue。原因是前者将阻塞调用Take的线程,直到项目出现在队列中。当处理Contract实例的线程在获取所有线程之前清除队列时,这将非常有用。

总的来说,你的策略非常可靠。我用它所有的时间。它通常被称为生产者 - 消费者模式。当处理涉及超过2个阶段时,它被称为管道模式。在这种情况下,您将拥有2个或更多队列,而不是典型的队列。您可以想象每个阶段通过另一个队列将工作项转发到下一个阶段的场景。