2

情報ログを維持する必要があります。これらのログは多数のスレッドから同時に書き込むことができますが、必要な場合は1つのスレッドのみを使用してデキューし、コレクションのデキューの間に約5秒の休憩を取ります。

以下は、デキューするために作成したコードです。

if (timeNotReached)
{
   InformationLogQueue.Enqueue(informationLog);
}
else
{
    int currentLogCount = InformationLogQueue.Count;
            var informationLogs = new List<InformationLog>();
            for (int i = 0; i < currentLogCount; i++)
            {
                InformationLog informationLog1;
                InformationLogQueue.TryDequeue(out informationLog1);
                informationLogs.Add(informationLog1);
            }
    WriteToDatabase(informationLogs);
}

デキューした後、データベースに挿入するためにListofInformationLogを必要とするLINQの挿入メソッドに渡します。

これは正しい方法ですか、それともこれを行うための他の効率的な方法はありますか?

4

2 に答える 2

5

ConcurrentQueue<T>次のような拡張メソッドを介して、Linqステートメントで直接使用できます。

static IEnumerable<T> DequeueExisting<T>(this ConcurrentQueue<T> queue)
{
    T item;
    while (queue.TryDequeue(out item))
        yield return item;
}

List<T>これにより、新しいオブジェクトとオブジェクトを継続的に割り当てる必要がなくなりConcurrentQueue<T>ます。

于 2012-09-04T08:40:10.590 に答える
2

ここで説明されているように、おそらく ConcurrentQueue<T>経由を使用する必要があります。BlockingCollection<T>


このようなもの、

private BlockingCollection<InformationLog> informationLogs = 
    new BlockingCollection<InformationLog>(new ConcurrentQueue<InformationLog>);

次に、コンシューマスレッドで実行できます

foreach(var log in this.informationLogs.GetConsumingEnumerable())
{
    // process consumer logs 1 by 1. 
}

さて、ここに複数のアイテムを消費するための答えがあります。消費スレッドでこれを行います、

InformationLog nextLog;
while (this.informationLogs.TryTake(out nextLog, -1))
{
    var workToDo = new List<informationLog>();
    workToDo.Add(nextLog);

    while(this.informationLogs.TryTake(out nextLog))
    {
        workToDo.Add(nextLog);
    }

    // process workToDo, then go back to the queue.
}

最初のwhileループは、キューからアイテムを無限の待機時間で取得します。キューでの追加が完了すると、つまりCompleteAdding呼び出されると、キューが空になると、この呼び出しはfalse遅滞なく返されます。

内側のwhileループは、50ミリ秒のタイムアウトでアイテムを取得します。これは、必要に応じて調整できます。キューが空になると、キューが返さfalseれ、作業のバッチを処理できます。

于 2012-09-04T08:17:41.777 に答える