问题描述
考虑以下code。
static class X
{
public static int Value = Task.Run(() => 0).Result;
}
class Program
{
static void Main(string[] args)
{
var value = X.Value;
}
}
在静态初始化调用 Task.Run
然后结果
使程序永久冻结。为什么呢?
Calling Task.Run
and then Result
in the static initializer causes the program to permanently freeze. Why?
推荐答案
您所看到的CLR的类的初始化锁僵局。
You are seeing deadlock on the CLR's class initialization lock.
基本上,没有在类 X
可以使用,直到类初始化。但是,你的匿名方法()=> 0
被编译到类中的一员。类初始化将无法完成,直到工作
可以完成,但工作
无法完成,因为这取决于这是不允许的方法来运行,直到类的初始化完成。
Basically, nothing in the class X
can be used until the class is initialized. But your anonymous method () => 0
is compiled to a member of the class. The class initialization won't complete until the Task
can complete, but the Task
can't complete because it depends on a method that isn't allowed to run until the initialization of the class is complete.
僵局。
您的例子显然是人为的,所以这是不可能提供意见,以如何解决你的实际问题。在这个特殊的例子,你可以替换 Task.FromResult(0)。结果初始化;
当然,这更是做作,但是,如果这是真正有用的,你只是分配 0
到外地。
Your example is clearly contrived, so it's impossible to provide advice as to how to fix your real-world problem. In this particular example, you could replace the initialization with Task.FromResult(0).Result;
but of course that's even more contrived; if that were actually usable, you'd just assign 0
to the field.
不过,无论您的真实世界的场景是,该办法解决它是不是造成这样一种情况之类的初始化依赖于一些外部组件需要的类,它完成。你可能会考虑,例如,使用延迟< T>
初始化值,或干脆直接调用方法(这将是允许的)
But whatever your real-world scenario is, the way to fix it is to not create a situation where initialization of the class depends on some external component needing that class for it to complete. You might consider, for example, using Lazy<T>
to initialize the value, or to just call the method directly (which would be allowed).
无论一个例子是人为的还是不行,还有从来没有在启动工作
只能立即冻结当前线程,直到它完成的任何一点。所以,如果您有任何code,虽然不是真的完全像这个例子中,仍然没有有效的同样的事情,明显的解决方法是改变它的串行执行,单线程的方式。
Whether an example is contrived or not, there's never any point in starting a Task
only to immediately block the current thread until it completes. So if you have any code that, while not literally exactly like this example, still does effectively the same thing, the obvious fix is to change it to execute in a serial, single-threaded manner.
这篇关于Task.Run在静态初始化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!