处理来自数据库的队列时系统范围的互斥锁的替代方案

本文关键字:方案 范围 系统 数据库 队列 处理 | 更新日期: 2023-09-27 18:33:24

我有一些(实体框架 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 方法外部的多线程。事实上,我希望多个进程/应用程序域同时运行此代码。如何防止多个进程从队列中选取同一项目?我可以使用系统范围的(命名的(互斥锁,但我看到它们非常慢。我正在寻找某种原子"拉动并标记为正在进行中"。我正在使用SqlServerCE4作为数据存储。

处理来自数据库的队列时系统范围的互斥锁的替代方案

最好

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

  1. 向表格中添加"进行中"字段
  2. 确保为表启用了乐观并发(例如,通过 RowVersion(
  3. 查询时,查询既不是正在进行也不是完成的内容
  4. 获取第一个实体后,更新该"进行进度"字段以指示您已获取它,然后保存更改。
  5. 如果发生并发异常,请进行处理。这意味着其他人已经在您同时抓取了此物品,但他们先保存了。在这种情况下,请重新启动循环并查找下一个循环。
  6. 如果未引发异常,请按原样处理,但您必须使用适当的错误处理来确保始终清除 InProgress,即使在您将其标记为 InProgress 之后的某个时间点引发异常也是如此。