Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/opengl/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# ConcurrentBag<;MyType>;Vs列表<;MyType>;_C#_.net_Vb.net_Multithreading - Fatal编程技术网

C# ConcurrentBag<;MyType>;Vs列表<;MyType>;

C# ConcurrentBag<;MyType>;Vs列表<;MyType>;,c#,.net,vb.net,multithreading,C#,.net,Vb.net,Multithreading,使用ConcurrentBag(MyType)与仅使用列表(MyType)相比有什么优势? 声明 ConcurrentBag(Of T)是线程安全的 bag实施,针对以下方面进行了优化 相同线程将 同时生产和消费数据 装在袋子里 那么优势是什么呢?我可以理解并发名称空间中其他集合类型的优势,但这一点让我感到困惑。与其他并发集合不同,ConcurrentBag针对单线程使用进行了优化。 与List不同,ConcurrentBag可以从多个线程同时使用 我认为您应该将其理解为“当多个线程访问容器时,

使用ConcurrentBag(MyType)与仅使用列表(MyType)相比有什么优势? 声明

ConcurrentBag(Of T)是线程安全的 bag实施,针对以下方面进行了优化 相同线程将 同时生产和消费数据 装在袋子里


那么优势是什么呢?我可以理解并发名称空间中其他集合类型的优势,但这一点让我感到困惑。

与其他并发集合不同,
ConcurrentBag
针对单线程使用进行了优化。

List
不同,
ConcurrentBag
可以从多个线程同时使用

我认为您应该将其理解为“当多个线程访问容器时,每个线程都可能产生和/或消耗数据”,它绝对适用于并行场景。

这里最大的优点是,
ConcurrentBag
可以安全地从多个线程访问,而
LisT
则不能。如果线程安全访问对您的场景很重要,那么像
ConcurrentBag
这样的类型可能比
List
+手动锁定更有利。在我们真正回答这个问题之前,我们需要更多地了解您的场景


另外,
List
是一个有序集合,而
ConcurrentBag
不是

在内部,ConcurrentBag使用几个不同的列表实现,每个写入线程一个列表

你引用的那句话的意思是,当从包中读取时,它将优先考虑为该线程创建的列表。也就是说,它将首先检查该线程的列表,然后再冒险与另一个线程的列表争用


这样,当多个线程同时读取和写入时,它可以最小化锁争用。当读取线程没有列表或其列表为空时,它必须锁定分配给其他线程的列表。但是,如果您有多个线程都在读取和写入它们自己的列表,那么您将永远不会有锁争用;我会说本地锁速度更快,但差异可以忽略不计(或者我设置了测试)

性能分析:

private static IEnumerable<string> UseConcurrentBag(int count)
    {
        Func<string> getString = () => "42";

        var list = new ConcurrentBag<string>();
        Parallel.For(0, count, o => list.Add(getString()));
        return list;
    }

    private static IEnumerable<string> UseLocalLock(int count)
    {
        Func<string> getString = () => "42";
        var resultCollection = new List<string>();
        object localLockObject = new object();
        Parallel.For(0, count, () => new List<string>(), (word, state, localList) =>
        {
            localList.Add(getString());
            return localList;
        },
            (finalResult) => { lock (localLockObject) resultCollection.AddRange(finalResult); }
            );

        return resultCollection;
    }

    private static void Test()
    {
        var s = string.Empty;
        var start1 = DateTime.Now;
        var list = UseConcurrentBag(5000000);
        if (list != null)
        {
            var end1 = DateTime.Now;
            s += " 1: " + end1.Subtract(start1);
        }

        var start2 = DateTime.Now;
        var list1 = UseLocalLock(5000000);
        if (list1 != null)
        {
            var end2 = DateTime.Now;
            s += " 2: " + end2.Subtract(start2);
        }

        if (!s.Contains("sdfsd"))
        {
        }
    }
私有静态IEnumerable UseConcurrentBag(int计数)
{
Func getString=()=>“42”;
var list=新的ConcurrentBag();
For(0,count,o=>list.Add(getString());
退货清单;
}
私有静态IEnumerable UseLocalLock(int计数)
{
Func getString=()=>“42”;
var resultCollection=新列表();
对象localLockObject=新对象();
Parallel.For(0,count,()=>new List(),(word,state,localList)=>
{
Add(getString());
返回localList;
},
(finalResult)=>{lock(localLockObject)resultCollection.AddRange(finalResult);}
);
返回结果集合;
}
专用静态空隙试验()
{
var s=string.Empty;
var start1=DateTime.Now;
var列表=UseConcurrentBag(5000000);
如果(列表!=null)
{
var end1=DateTime.Now;
s+=“1:”+end1.减法(start1);
}
var start2=DateTime.Now;
var list1=UseLocalLock(5000000);
if(list1!=null)
{
var end2=DateTime.Now;
s+=“2:”+end2.减法(开始2);
}
如果(!s.Contains(“sdfsd”))
{
}
}
使用ConcurrentBag对其自身运行3次,记录为5M的错误幅度

“1:00:00.4550455 2:00:00:00.4090409”
“1:00:00:00.4190419 2:00:00:00.4730473”
“1:00:00:00.4780478 2:00:00:00.3870387”

3次运行ConcurrentBag与本地锁,记录为5M:

“1:00:00:00.5070507 2:00:00:00.3660366”
“1:00:00:00.4470447 2:00:00:00.2470247”
“1:00:00:00.4420442 2:00:00:00.2430243”

有5000万的记录

“1:00:00:04.7354735 2:00:00:04.7554755”
“1:00:00:04.2094209 2:00:00:03.2413241”

我想说本地锁稍微快一点

更新:在(Xeon X5650@2.67GHz 64位Win7 6内核)上,“本地锁”的性能似乎更好

有5000万张唱片

1:00:00:09.7739773 2:00:00:06.8076807
1:00:00:08.8858885 2:00:00:04.6184618
1:00:00:12.5532552 2:00:00:06.4866486


+这是正确的解释。另请看:我很想看看它是如何伸缩的。随着内核数量的增加,锁争用将增加时间。ConcurrentBag将为每个线程使用一个列表,这样就不会增加争用(不过,更大的内存,这是一个古老的权衡)。@MattC Hi Matt,我在E3-1225 v3@3.20Ghz 16GB 64位Win7上运行了这个。它是4核CPU,如果你能找到不同的机器,有不同数量的核心,请运行上面的代码,我会很高兴把结果纳入答案。谢谢。50万张唱片。1:00:00:09.7739773 2:00:00:06.8076807 1:00:00:08.8858885 2:00:00:04.6184618 1:00:00:12.5532552 2:00:00:00:06.4866486 Xeon X5650@2.67GHz 64位Win7 6 core在我的机器上非常可变@MattC比率非常接近,足以证实“本地锁”的速度更快(9.7739773/6.8076807=1.43572792713、8.8858885/4.6184618=1.92399307059、12.5532552/6.4866486=1.9352451)是的,我同意如果您所做的只是将锁添加到列表中,那么锁就是我将如何操作的。