Parallel.For 中 StringBuilder 的线程安全
Thread Safety of StringBuilder in Parallel.For
我创建了一个结构,比如 AStruct
,并覆盖了它的 ToString()
方法。然后我写了一个平行于 return 一些 AStruct
并将它们放在一个列表中所以我可以使用 StreamWriter
来输出它们,比如
StreamWriter sw = new StreamWriter(@"ABC.txt");
StringBuilder sb = new StringBuilder();
List<AStruct> AList = new List<AStruct>();
Parallel.For(0,10,i => // generate 10 AStruct(s)
{
AList.Add(DoSomethingThatReturnsAStruct);
});
for(int i =0; i< AList.Count();i++) //put in a StringBuilder
{
sb.AppendLine(AList[i].ToString());
}
sw.Write(sb.ToString());
sw.Close();
问题是输出文件只打印了AList的7/8行,而AList实际上得到了所有的10个元素。我想知道这是否与 StringBuilder 的线程安全有关。有人可以解释为什么不是所有行都输出吗?
在你上面的代码中,StringBuilder
的实例永远不会被 main
线程(或创建 sw
的任何线程)以外的任何东西 accessed/modified 所以 [ StringBuilder
的 =36=] 不相关 但是 你有一个更大的错误,在处理多个线程时你应该永远记住它。
Never ever modify a shared resource by multiple threads unless that
resource is thread-safe
您正在从不同线程更新 AList
,因此要么使用 lock
来同步访问,要么使用 thread-safe 集合,例如ConcurrentQueue
(保证订单)或 ConcurrentBag
(不保证订单)
您还将 9 个条目添加到 AList
而不是 10.
最后是您修改后的代码,它产生了预期的结果。
var sw = new StreamWriter(@"ABC.txt");
try
{
var AList = new List<AStruct>();
var locker = new object();
Parallel.For(0, 10, i => // generate 10 AStruct(s)
{
lock (locker) { AList.Add(new AStruct()); }
});
var sb = new StringBuilder();
for (int i = 0; i < AList.Count; i++) //put in a StringBuilder
{
sb.AppendLine(AList[i].ToString());
}
sw.Write(sb.ToString());
} finally
{
sw.Close();
}
我创建了一个结构,比如 AStruct
,并覆盖了它的 ToString()
方法。然后我写了一个平行于 return 一些 AStruct
并将它们放在一个列表中所以我可以使用 StreamWriter
来输出它们,比如
StreamWriter sw = new StreamWriter(@"ABC.txt");
StringBuilder sb = new StringBuilder();
List<AStruct> AList = new List<AStruct>();
Parallel.For(0,10,i => // generate 10 AStruct(s)
{
AList.Add(DoSomethingThatReturnsAStruct);
});
for(int i =0; i< AList.Count();i++) //put in a StringBuilder
{
sb.AppendLine(AList[i].ToString());
}
sw.Write(sb.ToString());
sw.Close();
问题是输出文件只打印了AList的7/8行,而AList实际上得到了所有的10个元素。我想知道这是否与 StringBuilder 的线程安全有关。有人可以解释为什么不是所有行都输出吗?
在你上面的代码中,StringBuilder
的实例永远不会被 main
线程(或创建 sw
的任何线程)以外的任何东西 accessed/modified 所以 [ StringBuilder
的 =36=] 不相关 但是 你有一个更大的错误,在处理多个线程时你应该永远记住它。
Never ever modify a shared resource by multiple threads unless that resource is thread-safe
您正在从不同线程更新 AList
,因此要么使用 lock
来同步访问,要么使用 thread-safe 集合,例如ConcurrentQueue
(保证订单)或 ConcurrentBag
(不保证订单)
您还将 9 个条目添加到 AList
而不是 10.
最后是您修改后的代码,它产生了预期的结果。
var sw = new StreamWriter(@"ABC.txt");
try
{
var AList = new List<AStruct>();
var locker = new object();
Parallel.For(0, 10, i => // generate 10 AStruct(s)
{
lock (locker) { AList.Add(new AStruct()); }
});
var sb = new StringBuilder();
for (int i = 0; i < AList.Count; i++) //put in a StringBuilder
{
sb.AppendLine(AList[i].ToString());
}
sw.Write(sb.ToString());
} finally
{
sw.Close();
}