队列< T>下并发给出不同的结果为不同类型的队列、不同类型、不同、结果

2023-09-04 04:08:51 作者:七野.

我刚刚认识一些新的.NET并发集合像ConcurrentDictionary和ConcurrentQueue,我跑了一些测试,看看当我写平行队列会发生什么。

于是我就这样的:

 私有静态无效ParallelWriteToQueue(队列< INT>队列)
    {
        秒表SW = Stopwatch.StartNew();
        的Parallel.For(1,1000001中,(i)=> queue.Enqueue(ⅰ));
        sw.Stop();
        Console.WriteLine(常规INT队列 - + queue.Count +时间+ sw.ElapsedMilliseconds);
    }
 

当我以为我得到了一个异常:

 源阵列是不是足够长的时间。检查SRCINDEX和长度,以及阵列的下限。
 

所以这个队列无法处理的并发连接,队列为predicted。

但是,当我改变了队列字符串类型的,没有例外,并将结果写入类似

 普通字符串队列 -  663209 time117
 
3D Xpoint加QLC的组合,开辟2C存储新品类

这意味着只有大约663k是EN-排队。

为什么会出现也不例外?

发生了什么事所有的不带连接排队的项目?

这是同样的功能与队列

 私有静态无效ParallelWriteToQueue(队列<字符串>队列)
    {
        秒表SW = Stopwatch.StartNew();
        的Parallel.For(1,100001,(ⅰ)=> queue.Enqueue(i.ToString()));
        sw.Stop();
        Console.WriteLine(常规字符串队列 - + queue.Count +时间+ + sw.ElapsedMilliseconds);
    }
 

解决方案

无论你是否得到一个异常无关,与你放入队列的类型。它具有不确定性,我可以复制的例外两种类型,我可以重现的情况下无一例外也为两种类型 - 不改变code

运行下面的代码片段显示了这一点:

  INT异常= 0;
INT noExceptions = 0;
为(中间体X = 0 X  - 小于100 ++ x)的
{
    队列< INT> Q =新的队列和LT;诠释>();
    尝试
    {
        的Parallel.For(1,1000001中,(i)=> q.Enqueue(ⅰ));
        ++ noExceptions;
    }
    抓住
    {
        ++异常;
    }
}

Console.WriteLine(运行出现异常:{0}运行没有:{1},异常noExceptions);
 

输出是一样的东西运行出现异常:96运行没有:4

原因是 - 正如其他人已经提到 - 即队列不是线程安全的。这里发生的被称为比赛条件。

I'm just getting to know some of the new .NET concurrent collections like ConcurrentDictionary and ConcurrentQueue and I was running some tests to see what happens when I write parallel to the Queue.

So I ran this:

    private static void ParallelWriteToQueue(Queue<int> queue)
    {
        Stopwatch sw = Stopwatch.StartNew();
        Parallel.For(1,1000001,(i) => queue.Enqueue(i));
        sw.Stop();
        Console.WriteLine("Regular int Queue - " + queue.Count + " time" + sw.ElapsedMilliseconds);
    }

And as I thought I got the next exception:

Source array was not long enough. Check srcIndex and length, and the array's lower bounds.

So this Queue can't handle concurrent en-queues as predicted.

But, When I changed the type of the queue to string, there was no exception, and the result writes something like

Regular string Queue - 663209 time117

Which means that only about 663k were en-queued.

Why was there no exception?

What happened to all of the not en-queued items?

this is the same function with Queue

    private static void ParallelWriteToQueue(Queue<string> queue)
    {
        Stopwatch sw = Stopwatch.StartNew();
        Parallel.For(1, 100001, (i) => queue.Enqueue(i.ToString()));
        sw.Stop();
        Console.WriteLine("Regular string Queue - " + queue.Count + " time" + +sw.ElapsedMilliseconds);
    }

解决方案

Whether or not you get an exception has nothing to do with the type you put in the queue. It is non-deterministic, I can reproduce the exception for both types and I can reproduce the case without exception also for both types - without changes to the code.

Running the following snippet shows this:

int exceptions = 0;
int noExceptions = 0;
for (int x = 0; x < 100; ++x)
{
    Queue<int> q = new Queue<int>();
    try
    {
        Parallel.For(1,1000001,(i) => q.Enqueue(i)); 
        ++noExceptions;
    }
    catch
    {
        ++exceptions;
    }
}

Console.WriteLine("Runs with exception: {0}. Runs without: {1}", exceptions, noExceptions);

The output is something like Runs with exception: 96. Runs without: 4

The reason is - as others already mentioned - that Queue is not thread safe. What happens here is called "Race condition".