我有一个非常基本的问题,更多地围绕以下概念ConcurrentQueue
。队列是先进先出的。当多个线程开始访问时,我们如何保证先进先出呢?
假设我添加了Apple
, Oranges
, Lemon
, Peach
and Apricot
- 以该顺序。首先TryTake
应该返回Apple
。但是当多个线程开始给出自己的线程时会发生什么TryTake
要求?是否有可能当一个线程可以返回时Lemon
甚至在另一个线程返回之前Apple
?我假设其他项目也将被返回,直到队列为空。但这些回报是否会遵循先进先出的基本原则?
的行为ConcurrentQueue
本身总是 FIFO。
当我们谈论线程“返回”项目时ConcurrentQueue
,我们正在讨论一个涉及使项目出列的操作and执行某种操作,使您能够观察已出列的内容。无论是打印输出还是将该项目添加到另一个列表中,在检查之前您实际上并不知道哪个项目已从队列中取出。
虽然队列本身是 FIFO,但您无法预测其他事件(例如检查出队项目)发生的顺序。这些项目将从 FIFO 中出列,但您可能无法观察到按该顺序从队列中出来的内容。不同的线程可能不会按照从队列中删除项目的完全相同的顺序执行检查或输出。
换句话说,它将会发生 FIFO,但它可能会也可能不会总是看起来像这样。你不会想从一个ConcurrentQueue
如果处理项目的确切顺序很重要,则可以同时进行。
如果您要对此进行测试(我正要写一些东西),那么您可能会发现大多数时候项目都按照精确的 FIFO 顺序进行处理,但有时却不会。
这是一个控制台应用程序。它将
- 将 1 到 5000 之间的数字插入
ConcurrentQueue
,单线程。
- 执行并发操作以使每个项目出列并将它们移动到另一个项目
ConcurrentQueue
. 这就是“多线程消费者”。
- 读取第二个队列中的项目(再次是单线程)并报告任何不按顺序排列的数字。
我运行了很多次,没有出现任何乱序的情况。但大约 50% 的情况下,它只报告一些不按顺序排列的数字。因此,如果您指望所有数字都按其原始顺序进行处理,那么大多数情况下几乎所有数字都会发生这种情况。但后来就不行了。如果您不关心确切的顺序,那很好,但如果您关心的话,就会出现错误且不可预测。
结论 - 不依赖于多线程操作的确切顺序。
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();
}
}
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)