1

我有一些(实体框架 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 作为数据存储。

4

1 回答 1

3

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

  1. 将“InProgress”字段添加到您的表中
  2. 确保您为表启用了乐观并发(例如通过 RowVersion)
  3. 查询时,查询既不是 InProgress 也不是 Complete 的事物
  4. 当您获得第一个实体时,更新 InProgress 字段以表明您已抓取它,然后 SaveChanges。
  5. 如果发生并发异常,请处理它。这意味着其他人已经在您获取此项目的同时获取了此项目,但他们先保存了。在这种情况下,重新启动循环并寻找下一个循环。
  6. 如果没有引发异常,则照常处理,但必须使用适当的错误处理以确保始终清除 InProgress,即使在将异常标记为 InProgress 后的某个时间点引发异常也是如此。
于 2012-05-04T21:27:56.313 回答