繁体   English   中英

循环计数!= list.Count - 填充列表 <string> 在新线程中

[英]Loop count != list.Count - Populating List<string> in new threads

为什么以下代码的结果(list.Count)总是大约是18100而不是预期的19000?

    var list = new List<string>(19000);
    List<Task> tl = new List<Task>(19000);

    for (int q = 0; q < 19000; q++)
    {
        tl.Add(Task.Factory.StartNew(() =>
        {
            var k = "something";
            list.Add(k);
        }));
    }

    Task.WaitAll(tl.ToArray());
    Console.WriteLine(list.Count);

问题是List<T>不是线程安全的。

任务并行

您可以在System.Collections.Concurrent使用线程安全的集合,并使用ConcurrentBag<>类型。 试试这个:

var list = new ConcurrentBag<string>();

List<Task> tl = new List<Task>(19000);

for (int q = 0; q < 19000; q++)
{
    tl.Add(Task.Factory.StartNew(() =>
    {
        var k = "something";
        list.Add(k);
    }));
}

Task.WaitAll(tl.ToArray());
Console.WriteLine(list.Count);

还有其他线程安全类型,如ConcurrentQueue<>ConcurrentStack<>等。

处理非线程安全对象 - 锁定(对象)

另一方面,您可以使用lock keyworkd来阻止其他线程访问同一个语句块。 在这种情况下,您可以使用List<T>和非线程安全对象作为示例:

该对象必须对所有线程都可见,因此,您可以在类范围内声明它,对于示例:

private static object _sync = new object();

在它之后,尝试在需要修改时锁定此实例,对于示例:

var list = new List<string>(19000);

List<Task> tl = new List<Task>(19000);

for (int q = 0; q < 19000; q++)
{
    tl.Add(Task.Factory.StartNew(() =>
    {
       lock(_sync)
       {
          var k = "something";
          list.Add(k);
       }
    }));
}

Task.WaitAll(tl.ToArray());
Console.WriteLine(list.Count);

List<T>类不是线程安全的,请参阅MSDN

线程安全

此类型的公共静态(在Visual Basic中为Shared)成员是线程安全的。 任何实例成员都不保证是线程安全的。

在List上执行多个读取操作是安全的,但如果在读取集合时修改了集合,则可能会出现问题。 要确保线程安全,请在读取或写入操作期间锁定集合。 要使多个线程可以访问集合以进行读写,您必须实现自己的同步。 对于具有内置同步的集合,请参阅System.Collections.Concurrent命名空间中的类。 有关本质上线程安全的替代方法,请参阅ImmutableList类。

List(T)不是线程安全的。

https://msdn.microsoft.com/en-us/library/6sh2ey19%28v=vs.110%29.aspx

此类型的公共静态成员是线程安全的。 任何实例成员都不保证是线程安全的。

因此,不能保证从多个线程分配给它可以产生所需的结果。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM