简体   繁体   English

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

[英]alternatives to system-wide mutex when processing queue from DB?

I've got some (Entity Framework 4) code that looks like this: 我有一些(实体框架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);
    }

    //...
}

I want to change it to be multithreaded external to the ProcessItems method. 我想将它更改为ProcessItems方法外部的多线程。 In fact, I want multiple processes/appDomains to be running this code simultaneously. 实际上,我希望多个进程/ appDomains同时运行此代码。 How do I keep multiple processes from picking the same item out of the Queue? 如何让多个进程从队列中挑选相同的项目? I could use a system-wide (named) mutex, but I've seen those be terribly slow. 我可以使用系统范围(命名)互斥,但我看到那些非常慢。 I'm looking for some kind of atomic "pull and mark as in progress". 我正在寻找某种原子“拉动和标记正在进行中”。 I'm using SqlServerCE4 as the data storage. 我正在使用SqlServerCE4作为数据存储。

It might be better to use an actual message queue like MSMQ, Azure Queues, or even Sql Server Service Broker (wouldn't work with CE, of course). 使用像MSMQ,Azure队列甚至是Sql Server Service Broker这样的实际消息队列可能会更好(当然不适用于CE)。 Something like Redis might be easier too. 像Redis这样的东西也可能更容易。 If none of those are an option, you'll probably have to do something like the following: 如果这些都不是一个选项,您可能需要执行以下操作:

  1. Add an "InProgress" field to your table 在表格中添加“InProgress”字段
  2. Ensure that you have optimistic concurrency enabled for your table (eg via a RowVersion) 确保为表启用了乐观并发(例如,通过RowVersion)
  3. When you query, query for things that are neither InProgress nor Complete 查询时,查询既不是InProgress也不是Complete的东西
  4. When you get the first entity, update that InProgress field to indicate you've grabbed it, and SaveChanges. 当你获得第一个实体时,更新该InProgress字段以表明你已经抓住它,并保存SaveChanges。
  5. Handle the concurrency exception if it happens. 如果发生并发处理并发异常。 This means someone else has already grabbed this item at the same time you did, but they saved first. 这意味着其他人已经同时抓住了这个项目,但他们先保存了。 In that case, restart your loop and look for the next one. 在这种情况下,重新启动循环并查找下一个循环。
  6. If no exception was thrown, process as you have been, except that you have to use appropriate error handling to make sure that InProgress always gets cleared, even if an exception is thrown at some point after you marked it InProgress. 如果没有抛出异常,则按原样进行处理,除非必须使用适当的错误处理以确保InProgress始终被清除,即使在将其标记为InProgress之后的某个时刻抛出异常也是如此。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM