从DB处理队列时,系统范围互斥的替代方案?

时间:2012-05-04 20:58:23

标签: c# entity-framework-4 sql-server-ce mutex

我有一些(Entity Framework 4)代码,如下所示:

class QueueItem{
    public bool Processed { get; set; }
    // ... other fields
}

class QueueContext: System.Data.Entity.DbContext
{
    public System.Data.Entity.DbSet<QueueItem> Queue { get; set; }

    public void ProcessItems()
    {
        do
        {
            var item = Queue.FirstOrDefault(q => !q.Processed);
            if(item == null) break;
            ProcessItem(item);
            item.Processed = true;
            SaveChanges();
        } while(true);
    }

    //...
}

我想将其更改为ProcessItems方法外部的多线程。实际上,我希望多个进程/ appDomains同时运行此代码。如何让多个进程从队列中挑选相同的项目?我可以使用系统范围(命名)互斥,但我看到那些非常慢。我正在寻找某种原子“拉动和标记正在进行中”。我正在使用SqlServerCE4作为数据存储。

1 个答案:

答案 0 :(得分:3)

最好使用实际的消息队列,如MSMQ,Azure队列,甚至是Sql Server Service Broker(当然不适用于CE)。像Redis这样的东西也可能更容易。如果这些都不是一个选项,您可能需要执行以下操作:

  1. 在表格中添加“InProgress”字段
  2. 确保为表启用了乐观并发(例如,通过RowVersion)
  3. 查询时,查询既不是InProgress也不是完整
  4. 的内容
  5. 当您获得第一个实体时,请更新该InProgress字段以表明您已抓住它,并保存SaveChanges。
  6. 如果发生并发处理并发异常。这意味着其他人已经同时抓住了这个项目,但他们先保存了。在这种情况下,重新启动循环并查找下一个循环。
  7. 如果没有抛出异常,请按原样处理,除非您必须使用适当的错误处理以确保InProgress始终被清除,即使在您将其标记为InProgress之后的某个时刻抛出异常。