ConcurrentQueue .Net:多线程使用者 [英] ConcurrentQueue .Net: Multithreaded consumer

查看:213
本文介绍了ConcurrentQueue .Net:多线程使用者的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个非常基本的问题,更多地是关于ConcurrentQueue的概念.队列是FIFO.当多个线程开始访问它时,我们如何保证FIFO? 假设我按顺序添加了AppleOrangesLemonPeachApricot.第一个TryTake应该返回Apple.但是,当多个线程开始发出自己的TryTake请求时会发生什么?当一个线程甚至在另一个线程可以返回Apple之前,是否有可能返回一个线程?我假设其他项目也将返回,直到队列为空.但是,这些收益是否将围绕FIFO的基本原理进行管理?

I had a very basic question which is more around concepts of ConcurrentQueue. A queue is FIFO. When multiple threads start accessing it, how do we guarantee FIFO? Suppose, I have added Apple, Oranges, Lemon, Peach and Apricot - in that order. The first TryTake should return Apple. But what happens when multiple threads starts giving their own TryTake requests? Would'nt there be a possibility that when one thread could return Lemon even before another thread could return Apple? I am assuming the other items will also be returned till the Queue is empty. But will these returns govern around the basic principles of FIFO?

推荐答案

ConcurrentQueue本身的行为始终是FIFO.

The behavior of the the ConcurrentQueue itself is always going to be FIFO.

当我们谈论线程从ConcurrentQueue返回"项目时,我们所谈论的是一项操作,该操作涉及将项目出队并执行某种操作,使您能够观察到已出队的东西.无论是打印输出还是将该项目添加到另一个列表中,您实际上都不知道从队列中取出了哪个项目,直到您对其进行检查.

When we talk about threads "returning" items from the ConcurrentQueue, we're talking about an operation that involves both dequeuing an item and performing some sort of an operation that enables you to observe what has been dequeued. Whether it's printing an output or adding that item to another list, you don't actually know which item has been taken out of the queue until you inspect it.

虽然队列本身是FIFO,但是您无法预测其他事件(例如检查出队项目)的发生顺序.这些项目将以FIFO出队,但您可能无法观察到按该顺序从队列中出来的内容.不同的线程可能无法按照从队列中删除项目的完全相同的顺序执行检查或输出.

While the queue itself is FIFO, you can't predict the sequence in which those other events, such as inspecting the dequeued items, will occur. The items will be dequeued FIFO, but you may or may not be able to observe what comes out of the queue in that order. The different threads may not perform that inspection or output in exactly the same order in which they removed items from the queue.

换句话说,它将发生在FIFO中,但是它看起来或不一定总是像它一样.如果处理项目的确切顺序很关键,则您不想同时读取ConcurrentQueue.

In other words, it's going to happen FIFO but it may or may not always look like it. You wouldn't want to read from a ConcurrentQueue concurrently if the exact sequence in which the items handled was critical.

如果要对此进行测试(我要写点东西),那么您可能大多数时候会发现以精确的FIFO顺序进行处理的项目,但是偶尔都不会.

If you were to test this (I'm about to write something) then you'd probably find items getting processed in exact FIFO sequence most of the time, but then every once in a while they wouldn't be.

这是一个控制台应用程序.将要

Here's a console app. It's going to

  • 将1到5000之间的数字插入到单线程ConcurrentQueue中.
  • 执行并发操作以使这些项目中的每一项出队,并将它们移至另一个ConcurrentQueue. 这是多线程使用者".
  • 读取第二个队列中的项目(再次为单线程),并报告所有顺序不正确的数字.
  • insert the numbers from 1-5000 in a ConcurrentQueue, single-threaded.
  • perform concurrent operations to dequeue each of those items and move them to another ConcurrentQueue. This is the "multithreaded consumer."
  • Read the items in the second queue (single threaded, again) and report any numbers that are out of sequence.

很多次我运行它,但没有任何异常.但是,大约有50%的时间它只报告了一些不按顺序排列的数字.因此,如果您指望按原始顺序处理的所有数字,大多数情况下几乎所有数字都会发生.但是,事实并非如此.如果您不关心确切的顺序就可以了,但是如果您不关心确切的顺序就可以了.

Many times I run it and nothing is out of sequence. But about 50% of the time it reports just a few numbers out of sequence. So if you were counting on all of the numbers getting processed in their original sequence it would happen with almost all of the numbers most of the time. But then it wouldn't. That's fine if you don't care about the exact sequence, but buggy and unpredictable if you do.

结论-不依赖于多线程操作的确切顺序.

The conclusion - don't depend on the exact sequence of multithreaded operations.

using System;
using System.Collections.Concurrent;
using System.Linq;
using System.Threading.Tasks;

namespace ConcurrentQueueExperiment
{
    class Program
    {
        static void Main(string[] args)
        {
            var inputQueue = new ConcurrentQueue<int>();
            var outputQueue = new ConcurrentQueue<int>();
            Enumerable.Range(1,5000).ToList().ForEach(inputQueue.Enqueue);
            while (inputQueue.Any())
            {
                Task.Factory.StartNew(() =>
                {
                    int dequeued;
                    if (inputQueue.TryDequeue(out dequeued))
                    {
                        outputQueue.Enqueue(dequeued);
                    }
                });
            }
            int output = 0;
            var previous = 0;
            while (outputQueue.TryDequeue(out output))
            {
                if(output!=previous+1)
                    Console.WriteLine("Out of sequence: {0}, {1}", previous, output);
                previous = output;
            }
            Console.WriteLine("Done!");
            Console.ReadLine();
        }
    }
}

这篇关于ConcurrentQueue .Net:多线程使用者的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆