C# 看来ConcurrentBag不是线程安全的
我编写了一个程序,一个列表生成器方法返回包含许多字符串的IEnumerable字符串(一百万个项),我将其存储在字符串列表中,然后它将所有项以并行方式追加到StringBuilder实例中。Foreach。然后我打印了stringBuilderInstance.Length 问题是它不到一百万。 经过一段时间后,我意识到thetlist集合不是线程安全的,这导致了这个问题。 因此,我想到了2个解决方案: 1) 使用锁 2) 使用ConcurrentBag 当我使用lock时,它是正常的,长度为1百万,但是: 当我使用ConcurrentBag of string时,长度比我预期的要短强> 这个问题的根本原因是什么 列表创建者方法:C# 看来ConcurrentBag不是线程安全的,c#,multithreading,C#,Multithreading,我编写了一个程序,一个列表生成器方法返回包含许多字符串的IEnumerable字符串(一百万个项),我将其存储在字符串列表中,然后它将所有项以并行方式追加到StringBuilder实例中。Foreach。然后我打印了stringBuilderInstance.Length 问题是它不到一百万。 经过一段时间后,我意识到thetlist集合不是线程安全的,这导致了这个问题。 因此,我想到了2个解决方案: 1) 使用锁 2) 使用ConcurrentBag 当我使用lock时,它是正常的,长度为1
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();
}