Task.Run in Static Initializer

本文关键字:Initializer Static in Run Task | 更新日期: 2023-09-27 18:34:57

请考虑以下代码。

static class X
{
    public static int Value = Task.Run(() => 0).Result;
}
class Program
{
    static void Main(string[] args)
    {
        var value = X.Value;
    }
}

调用 Task.Run然后在静态初始值设定项中Result会导致程序永久冻结。为什么?

Task.Run in Static Initializer

您在 CLR 的类初始化锁上看到死锁。

基本上,在类初始化之前,类X中的任何内容都不能使用。但是您的匿名方法() => 0被编译为类的成员。在Task完成之前,类初始化不会完成,但Task无法完成,因为它依赖于在类初始化完成之前不允许运行的方法。

僵局。

你的例子显然是人为的,所以不可能提供关于如何解决你的现实世界问题的建议。在这个特定示例中,您可以将初始化替换为Task.FromResult(0).Result;但当然这更加人为;如果这确实可用,您只需将0分配给该字段。

但是,无论您的实际场景是什么,修复它的方法是不要创建类的初始化依赖于需要该类才能完成的某个外部组件的情况。例如,您可以考虑使用 Lazy<T> 来初始化值,或者直接调用该方法(这是允许的(。

无论示例是否人为,启动Task只是立即阻止当前线程直到它完成,都没有任何意义。因此,如果您有任何代码,虽然与此示例不完全相同,但仍然有效地执行相同的操作,那么明显的解决方法是将其更改为以串行、单线程方式执行。

我认为对问题的解释不正确。

基本上,在初始化类之前,不能使用类 X 中的任何内容。


但任务无法完成,因为它依赖于不是 允许运行,直到类的初始化完成。

如果是这样,在这种情况下,您应该会收到编译器错误,但不会在运行时死锁。

无论如何,这个代码是合法的

static class X
{
    public static int Value = Method();
    private static int Method()
    {
        return 0;
    }
}

这是对问题的解释。