C# 排队<;T>;在并发下,为不同类型提供不同的结果

C# 排队<;T>;在并发下,为不同类型提供不同的结果,c#,.net,collections,concurrency,C#,.net,Collections,Concurrency,我刚刚了解了一些新的.NET并发集合,如ConcurrentDictionary和ConcurrentQueue,我正在运行一些测试,以了解在并行写入队列时会发生什么 所以我运行了这个: private static void ParallelWriteToQueue(Queue<int> queue) { Stopwatch sw = Stopwatch.StartNew(); Parallel.For(1,1000001,(i) =

我刚刚了解了一些新的.NET并发集合,如ConcurrentDictionary和ConcurrentQueue,我正在运行一些测试,以了解在并行写入队列时会发生什么

所以我运行了这个:

    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);
    }
因此,此队列无法按预期处理并发排队

但是,当我将队列的类型更改为字符串时,没有异常,结果是这样写的

Regular string Queue - 663209 time117
这意味着只有大约663k排队

为什么没有例外

所有未排队的项目都发生了什么

这与队列的功能相同

    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);
    }
private static void ParallelWriteToQueue(队列队列)
{
秒表sw=Stopwatch.StartNew();
Parallel.For(11001,(i)=>queue.Enqueue(i.ToString());
sw.Stop();
Console.WriteLine(“常规字符串队列-”+Queue.Count+“time”++sw.elapsedmillyses);
}

由于您使用的是
Parallel.For()
,因此集合必须是线程安全的才能正常工作


<> >,考虑使用<代码> CONTRONTRONG/类>

< P>。因为您使用的是<>代码> .For()
,集合必须是<强>线程安全< /强>以提供正常工作。< /P>

>请考虑使用<代码> CONTRONTRONG/类>

,而不是按MSDN的线程安全。您所描述的其余行为都是偶然发生的,因为并发(多线程)写访问产生了冲突,这纯粹是基于

队列
不是线程安全的事实。

与之相反,根据MSDN,它不是线程安全的。您描述的其余行为都是由于并发(多线程)写访问引起的冲突而偶然发生的,这纯粹是基于
队列
不是线程安全的事实。

是否得到异常与您在队列中放置的类型无关。这是不确定的,我可以为这两种类型重现异常,也可以为这两种类型重现无异常的情况,而无需更改代码

运行以下代码段可以显示以下内容:

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);
int异常=0;
int noExceptions=0;
对于(int x=0;x<100;++x)
{
队列q=新队列();
尝试
{
对于(11000001,(i)=>q.Enqueue(i));
++无例外;
}
抓住
{
++例外情况;
}
}
WriteLine(“带异常运行:{0}。不带异常运行:{1}”,异常,无异常);
输出类似于带异常运行的
:96。运行时没有:4


原因是,正如其他人已经提到的,
Queue
不是线程安全的。这里发生的事情称为。

是否得到异常与您在队列中输入的类型无关。这是不确定的,我可以为这两种类型重现异常,也可以为这两种类型重现无异常的情况,而无需更改代码

运行以下代码段可以显示以下内容:

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);
int异常=0;
int noExceptions=0;
对于(int x=0;x<100;++x)
{
队列q=新队列();
尝试
{
对于(11000001,(i)=>q.Enqueue(i));
++无例外;
}
抓住
{
++例外情况;
}
}
WriteLine(“带异常运行:{0}。不带异常运行:{1}”,异常,无异常);
输出类似于带异常运行的
:96。运行时没有:4


原因是,正如其他人已经提到的,
Queue
不是线程安全的。这里发生的事情称为。

测试显示,标准集合实现不是线程安全的。异常是用int而不是字符串引发的,这很可能是偶然的,如果您再次尝试测试,可能会得到不同的结果


至于“丢失”的项目,无法确定-队列的内部状态可能由于多线程访问而损坏,因此计数本身可能错误,或者项目可能根本没有排队。

测试显示,标准集合实现不是线程安全的。异常是用int而不是字符串引发的,这很可能是偶然的,如果您再次尝试测试,可能会得到不同的结果



至于“丢失”项,无法确定-队列的内部状态可能由于多线程访问而损坏,因此计数本身可能是错误的,或者项目可能根本没有排队。

您只运行第二个并行for循环到100001,而不是1000001。@DanielHilgarth抱歉,我在复制之前更改了它。。。它运行相同次数的迭代undefined behavior is undefined。有时会出错,有时不会。@CodesInChaos这是最好、最简单的答案:)您只运行第二个并行for循环到100001,而不是1000001。@DanielHilgarth抱歉,我在复制之前更改了它。。。它运行相同次数的迭代undefined behavior is undefined。有时你会犯错误,有时你不会。@CodesInChaos这是最好最简单的答案:)我的问题不是关于这个,而是为什么它会给不同的人不同的结果types@Mithir,因为实现不是线程安全的。这不能保证什么!我的问题不是关于这一点,而是为什么它会给不同的人带来不同的结果types@Mithir,因为实现不是线程安全的。这不能保证什么!我自己也尝试过这个函数,但没有捕获异常,这是为什么?尝试将外部for循环的计数从100增加到1000。由于这是未定义的行为,因此是不确定的,因此可能有多种原因。也许你的电脑太快、太慢、内存太多或太少。真的很难说……对不起,我要换个说法。。。已引发异常,但未捕获。。。也就是说,死刑停止了,我拿到了l