【发布时间】:2015-11-18 20:27:31
【问题描述】:
以下代码运行没有问题:
// This code outputs:
// 3
// 2
// 1
//
// foo
// DotNetFiddle: https://dotnetfiddle.net/wDRD9L
public class Program
{
public static void Main()
{
Console.WriteLine("foo");
}
static Program()
{
var sb = new System.Text.StringBuilder();
var list = new List<int>() { 1,2,3 };
list.AsParallel().WithDegreeOfParallelism(4).ForAll(item => { sb.AppendLine(item.ToString()); });
Console.WriteLine(sb.ToString());
}
}
只要我将 sb.AppendLine 替换为对 Console.WriteLine 的调用,代码就会挂起,就像某处出现死锁一样。
// This code hangs.
// DotNetFiddle: https://dotnetfiddle.net/pbhNR2
public class Program
{
public static void Main()
{
Console.WriteLine("foo");
}
static Program()
{
var list = new List<int>() { 1,2,3 };
list.AsParallel().WithDegreeOfParallelism(4).ForAll(item => { Console.WriteLine(item.ToString()); });
}
}
起初我怀疑Console.WriteLine 不是线程安全的,但根据文档,它是线程安全的。
这种行为的解释是什么?
【问题讨论】:
-
这可能与此有关:stackoverflow.com/questions/15143931/… - 您在后台线程中调用 Console.WriteLine() 之前它被正确初始化。
-
你很幸运
sb.AppendLine,这个方法不是线程安全的,如果你有更多更长的字符串,你的字符串会是错误的,甚至有些会丢失。 -
对我来说,即使没有
Console.WriteLine在Program的静态构造函数中,它也会锁定。在 cctor 中调用ForAll(带有空的主体)会触发挂起。 (针对 4.5.2,VS 2013) -
我只是在这里猜测,但我认为
Program的静态构造函数在调用并行循环并且底层代码进入等待状态等待静态构造函数完成初始化时类型(从线程开始的地方)。如果将逻辑移到单独的静态函数中,它不会挂起。 -
可能重复这个:“stackoverflow.com/questions/5770478/…” Console.WriteLine 与它无关。
标签: c# .net parallel.foreach plinq