1

次のような(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を使用しています。

4

1 に答える 1

3

MSMQ、Azure Queues、さらにはSql Server Service Brokerなどの実際のメッセージキューを使用する方がよい場合があります(もちろん、CEでは機能しません)。Redisのようなものも簡単かもしれません。これらのいずれもオプションではない場合は、おそらく次のようなことを行う必要があります。

  1. テーブルに「InProgress」フィールドを追加します
  2. テーブルに対して楽観的同時実行性が有効になっていることを確認します(たとえば、RowVersionを介して)
  3. クエリを実行するときは、進行中でも完了でもないものをクエリします
  4. 最初のエンティティを取得したら、そのInProgressフィールドを更新して、それを取得したことを示し、SaveChangesを実行します。
  5. 同時実行例外が発生した場合は処理します。これは、他の誰かがあなたと同じ時間にこのアイテムをすでにつかんでいることを意味しますが、彼らは最初に保存しました。その場合は、ループを再開して次のループを探してください。
  6. 例外がスローされなかった場合は、適切なエラー処理を使用して、InProgressとマークした後のある時点で例外がスローされた場合でも、InProgressが常にクリアされるようにする必要があることを除いて、これまでどおりに処理します。
于 2012-05-04T21:27:56.313 に答える