12

または、スレッドを使用して CPU の半分以上を使い果たすことなくアイテムを自由にデキューできるようにするには、BlockingCollectionどちらの正しい使用法でしょうか?ConcurrentQueue

2 つのスレッドを使用していくつかのテストを実行していましたが、少なくとも 50 ~ 100 ミリ秒の Thread.Sleep がない限り、常に CPU の少なくとも 50% を使用していました。

以下は架空の例です。

private void _DequeueItem()
{
    object o = null;
    while(socket.Connected)
    {
        while (!listOfQueueItems.IsEmpty)
        {
            if (listOfQueueItems.TryDequeue(out o))
            {
                // use the data
            }
        }
    }
}

上記の例では、CPUが爆発しないようにthread.sleepを設定する必要があります。

注: IsEmpty チェックの while なしでも試してみましたが、結果は同じでした。

4

3 に答える 3

23

BlockingCollectionorConcurrentQueueではなく、while ループが原因です。

while(socket.Connected)
{
    while (!listOfQueueItems.IsEmpty)
    { /*code*/ }
}

もちろん、それはCPUをダウンさせます。キューが空の場合、while ループは次のようになります。

while (true) ;

これにより、CPU リソースが消費されます。

ConcurrentQueueこれは良い使い方ではありませんAutoResetEventので、アイテムが追加されるたびに通知されます。例:

private ConcurrentQueue<Data> _queue = new ConcurrentQueue<Data>();
private AutoResetEvent _queueNotifier = new AutoResetEvent(false);

//at the producer:
_queue.Enqueue(new Data());
_queueNotifier.Set();

//at the consumer:
while (true)//or some condition
{
    _queueNotifier.WaitOne();//here we will block until receive signal notification.
    Data data;
    if (_queue.TryDequeue(out data))
    {
        //handle the data
    }
}

をうまく使用するには、BlockingCollectionを使用しGetConsumingEnumerable()てアイテムが追加されるのを待つ必要があります。

//declare the buffer
private BlockingCollection<Data> _buffer = new BlockingCollection<Data>(new ConcurrentQueue<Data>());

//at the producer method:
_messageBuffer.Add(new Data());

//at the consumer
foreach (Data data in _buffer.GetConsumingEnumerable())//it will block here automatically waiting from new items to be added and it will not take cpu down 
{
    //handle the data here.
}
于 2011-07-01T09:28:06.957 に答える
7

BlockingCollectionこの場合、本当にクラスを使用したいと考えています。アイテムがキューに表示されるまでブロックするように設計されています。この性質のコレクションは、多くの場合、ブロッキング キューと呼ばれます。この特定の実装は、複数のプロデューサーと複数のコンシューマーにとって安全です。これは、自分で実装しようとすると、驚くほど正しく理解するのが難しいものです。を使用した場合のコードは次のようになりますBlockingCollection

private void _DequeueItem()
{
    while(socket.Connected)
    {
        object o = listOfQueueItems.Take();
        // use the data
    }
}

Takeキューが空の場合、メソッドは自動的にブロックします。スレッドをSleepWaitJoinCPU リソースを消費しない状態にする方法でブロックします。優れた点BlockingCollectionは、ローロック戦略も使用してパフォーマンスを向上させることです。これが意味することはTake、キューにアイテムがあるかどうかを確認し、そうでない場合は、スレッドのコンテキスト スイッチを防ぐために一時的にスピン待機を実行することです。キューがまだ空の場合、スレッドはスリープ状態になります。これは、同時実行に関して提供されるBlockingCollectionいくつかのパフォーマンス上の利点があることを意味します。ConcurrentQueue

于 2011-07-01T12:59:21.953 に答える
0

Thread.Sleep()キューが空の場合にのみ呼び出すことができます:

private void DequeueItem()
{
    object o = null;

    while(socket.Connected)
    {
        if (listOfQueueItems.IsEmpty)
        {
            Thread.Sleep(50);
        }
        else if (listOfQueueItems.TryDequeue(out o))
        {
            // use the data
        }
    }
}

それ以外の場合は、イベントの使用を検討する必要があります。

于 2011-07-01T09:30:37.000 に答える