Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/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不是线程安全的_C#_Multithreading - Fatal编程技术网

C# 看来ConcurrentBag不是线程安全的

C# 看来ConcurrentBag不是线程安全的,c#,multithreading,C#,Multithreading,我编写了一个程序,一个列表生成器方法返回包含许多字符串的IEnumerable字符串(一百万个项),我将其存储在字符串列表中,然后它将所有项以并行方式追加到StringBuilder实例中。Foreach。然后我打印了stringBuilderInstance.Length 问题是它不到一百万。 经过一段时间后,我意识到thetlist集合不是线程安全的,这导致了这个问题。 因此,我想到了2个解决方案: 1) 使用锁 2) 使用ConcurrentBag 当我使用lock时,它是正常的,长度为1

我编写了一个程序,一个列表生成器方法返回包含许多字符串的IEnumerable字符串(一百万个项),我将其存储在字符串列表中,然后它将所有项以并行方式追加到StringBuilder实例中。Foreach。然后我打印了stringBuilderInstance.Length

问题是它不到一百万。 经过一段时间后,我意识到thetlist集合不是线程安全的,这导致了这个问题。 因此,我想到了2个解决方案:

1) 使用

2) 使用ConcurrentBag

当我使用lock时,它是正常的,长度为1百万,但是:

当我使用ConcurrentBag of string时,长度比我预期的要短

这个问题的根本原因是什么

列表创建者方法:

public static List<string> CreateList()
{
    List<string> result = new List<string>();
    for (int i = 0; i < 1000000; i++)
    {
        result.Add(1.ToString());
    }
    return result;
}

提前感谢。

StringBuilder
不是线程安全的,这就是为什么一些
Append()
调用“丢失”的原因。因此,即使您的集合是线程安全的,您仍然需要锁


(另外,请参阅Servy的答案,了解为什么不需要集合是线程安全的。)

StringBuilder
不是线程安全的,这就是为什么一些
Append()
调用“丢失”的原因。因此,即使您的集合是线程安全的,您仍然需要锁


(另外,请参阅Servy的答案,了解为什么不需要集合是线程安全的。)

StringBuilder
不能从多个线程中进行变异,因此,当您尝试这样做时,为什么代码不起作用。注意,锁定是没有意义的;首先不要创建多个线程来完成工作,因为不能从多个线程完成工作。由于您从不从多个线程访问
ConcurrentBag
,因此使用它而不是
列表是毫无意义的,因为
StringBuilder
不能从多个线程中变异,因此当您尝试这样做时,为什么代码不起作用。注意,锁定是没有意义的;首先不要创建多个线程来完成工作,因为不能从多个线程完成工作。由于您从不从多个线程访问
ConcurrentBag
,因此使用它而不是
列表是毫无意义的,您不应该在这里锁定。正确的解决方案是不创建多个线程,而不是创建一堆线程来同步所有线程。但是当我使用字符串而不是stringbuilder时,它也给出了错误的答案,字符串是线程安全的。我说的对吗?@Parsa:String是不可变的;你的变量不是线程安全的。你不应该在这里锁定。正确的解决方案是不创建多个线程,而不是创建一堆线程来同步所有线程。但是当我使用字符串而不是stringbuilder时,它也给出了错误的答案,字符串是线程安全的。我说的对吗?@Parsa:String是不可变的;您的变量不是线程安全的。在尝试编写线程安全代码之前,您需要了解有关线程的更多信息。请了解Parallel.ForEach以线程安全的方式调用您传入第一个参数的IEnumerable,所以,对于那个论点,你用什么集合来传递并不重要。@Scott Chamberlain:如果并行。Foreach以线程安全的方式调用IEnumerable,为什么会出现这个问题?@Parsa你读过这两个答案吗?问题不是由IEnumerable引起的,而是由StringBuilder引起的。在尝试编写线程安全代码之前,您需要了解更多关于线程的信息。请了解Parallel.ForEach以线程安全的方式调用您传入第一个参数的IEnumerable,所以,对于那个论点,你用什么集合来传递并不重要。@Scott Chamberlain:如果并行。Foreach以线程安全的方式调用IEnumerable,为什么会出现这个问题?@Parsa你读过这两个答案吗?问题不是由IEnumerable引起的,而是由StringBuilder引起的。
public static void DoWithParallel_ThreadSafe()
{
    ConcurrentBag<string> listOfString = new ConcurrentBag<string>(CreateList());
    StringBuilder a = new StringBuilder();
    Action<string> appender = (number) =>
    {
        a.Append(number);
    };
    Parallel.ForEach(listOfString, appender);
    Console.WriteLine($"The string builder lenght : {a.Length}");
}
public static void DoWithParallel_UnsafeThread_Lock()
{
    List<string> listOfString = CreateList();
    StringBuilder a = new StringBuilder();
    Action<string> appender = (number) =>
    {
        lock (listOfString)
        {
            a.Append(number);
        }
    };
    Parallel.ForEach(listOfString, appender);
    Console.WriteLine($"The string builder lenght : {a.Length}");
}
static void Main(string[] args)
{
    DoWithParallel_UnsafeThread_Lock();
    DoWithParallel_ThreadSafe();
    Console.ReadKey();
}