【发布时间】:2018-06-26 16:29:25
【问题描述】:
我编写了一个程序,列表生成器方法返回 IEnumerable 字符串,包括大量字符串(100 万个项目),并将其存储在 List of string 中,然后将 StringBuilder 实例中的所有项目附加到 Parallel.Foreach。然后我打印了 stringBuilderInstance.Length 。
问题是它少于 1000000 。 在googling 之后,我意识到 List 集合不是线程安全的,这导致了这个问题。 所以我想到了 2 个解决方案:
1) 使用锁定
2) 使用 ConcurrentBag
当我使用 lock 时,没问题,长度是 1 百万,但是:
当我使用字符串的 ConcurrentBag 时,长度比我预期的要短!
这个问题的根本原因是什么?
List-Creator 方法:
public static List<string> CreateList()
{
List<string> result = new List<string>();
for (int i = 0; i < 1000000; i++)
{
result.Add(1.ToString());
}
return result;
}
使用并发包:
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();
}
提前谢谢你。
【问题讨论】:
-
在尝试编写线程安全代码之前,您需要了解有关线程的更多信息。
-
只是让您知道 Parallel.ForEach 以线程安全的方式调用您传递给第一个参数的 IEnumerable,因此您为该参数传递的集合并不重要。
-
@Scott Chamberlain:如果 Parallel.Foreach 以线程安全的方式调用 IEnumerable,为什么会出现这个问题?
-
@Parsa 你读过这两个答案了吗?问题不是IEnumerable引起的,是StringBuilder引起的。
标签: c# multithreading