我有一个相当简单的代码片段,但它似乎阻止了Task.WhenAll()。 Main函数只调用new Test()
。有人可以帮助找到根本原因吗?
internal class Test
{
public static async Task<int> Foo()
{
return 0;
}
static Test()
{
var taskList = new List<Task>();
for (int i = 0; i < 100; i++)
taskList.Add(Task.Run(() => Foo()));
Task.WhenAll(taskList.ToArray()).GetAwaiter().GetResult();
}
}
答案 0 :(得分:9)
CLR在运行静态构造函数时采用全局锁定。静态构造函数必须在其他线程可以在类上输入任何方法之前释放此锁。这是为了保证静态构造函数的运行,并且每个appdomain只完成一次。以下是线程更明确的问题。
class Test
{
static Test() {
var thread = new Thread(ThreadMethod);
thread.Start();
thread.Join();
}
private static void ThreadMethod()
{
}
}
在静态构造函数退出之前,新线程无法进入ThreadMethod
,但静态构造函数无法退出,直到线程结束,即死锁。
您的示例只是一个更复杂的版本,它使用Task.Run
而不是创建Thread
并启动它然后GetResult
阻止Thread.Join
阻止
答案 1 :(得分:3)
解决方案是实现您尝试通过其他机制进行的初始化。如果需要,可以在静态构造函数中启动任务,但修复代码,以便实例可以在静态构造函数之外等待结果。例如,使用Lazy<T>
:
private static readonly Lazy<int> _tasksResult = new Lazy<int>(
() => InitTest());
static int InitTest()
{
var taskList = new List<Task>();
for (int i = 0; i < 100; i++)
taskList.Add(Task.Run(() => Foo()));
return Task.WhenAll(taskList.ToArray()).GetAwaiter().GetResult();
}
或类似的东西(你真的不清楚你真正感兴趣的是什么结果,所以上面有一点挥手)。