【问题标题】:Lazy<T>: "The function evaluation requires all threads to run"Lazy<T>:“函数评估需要所有线程运行”
【发布时间】:2011-05-26 12:04:18
【问题描述】:

我有一个带有一些静态属性的静态类。我在一个静态构造函数中初始化了所有这些,但后来意识到这很浪费,我应该在需要时延迟加载每个属性。所以我转而使用System.Lazy&lt;T&gt; 类型来完成所有脏活,并告诉它不要使用它的任何线程安全功能,因为在我的例子中执行总是单线程的。

我最终上了以下课程:

public static class Queues
{
    private static readonly Lazy<Queue> g_Parser = new Lazy<Queue>(() => new Queue(Config.ParserQueueName), false);
    private static readonly Lazy<Queue> g_Distributor = new Lazy<Queue>(() => new Queue(Config.DistributorQueueName), false);
    private static readonly Lazy<Queue> g_ConsumerAdapter = new Lazy<Queue>(() => new Queue(Config.ConsumerAdaptorQueueName), false);

    public static Queue Parser { get { return g_Parser.Value; } }
    public static Queue Distributor { get { return g_Distributor.Value; } }
    public static Queue ConsumerAdapter { get { return g_ConsumerAdapter.Value; } }
}

在调试时,我注意到一条我从未见过的消息:

函数求值需要所有线程运行

在使用Lazy&lt;T&gt;之前,值是直接显示的。现在,我需要单击带有线程图标的圆形按钮来评估惰性值。这只发生在我正在检索.ValueLazy&lt;T&gt; 的属性上。展开实际 Lazy&lt;T&gt; 对象的调试器可视化节点时,Value 属性仅显示 null,没有任何消息。

该消息是什么意思,为什么在我的案例中显示?

【问题讨论】:

标签: c# visual-studio visual-studio-2010 lazy-loading visual-studio-debugging


【解决方案1】:

对我来说,我发现我有this.Configuration.LazyLoadingEnabled = false;= true; 并不重要,我的DBContext 中有没有这条线。从我对问题的阅读来看,它似乎发生了,因为一个线程正在发生并且调试器想要运行它的权限/在它触发它之前警告你。显然,在某些情况下,您甚至可以允许它按照 MUG4N 在此处的回答进行:Visual Studio during Debugging: The function evaluation requires all threads to run

但我发现我可以解决这个问题。

2 个选项:

  1. 在您的Queues 上添加.ToList()

    var q = db.Queues.OrderBy(e =&gt; e.Distributor).ToList();

  2. 我通过选择非公共成员 > _internalQuery > ObjectQuery > 结果视图找到了解决方法。

【讨论】:

    【解决方案2】:

    我为此苦苦挣扎了好几个小时,发现关于要求所有线程运行的原始错误消息具有误导性。我正在从新解决方案访问现有数据库,并在新解决方案中创建新的Entity Framework 实体POCOs 和数据访问层以访问和映射到DB

    我最初做错了两件事。我没有在我的 C# 实体 POCO 中正确定义主键,而我正在访问的 tableDB 中有一个唯一的模式(它不是 dbo.tablename 而是 edi.tablename)。

    在我的DbContext.cs 文件中,我执行了以下操作以将表映射到正确的架构下。一旦我纠正了这些问题,错误就消失了,它工作得很好。

    protected override void OnModelCreating(DbModelBuilder dbModelBuilder)
    {
        base.OnModelCreating(dbModelBuilder);
        dbModelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
        dbModelBuilder.Entity<TableName>().ToTable("TableName", schemaName: "EDI");
    }
    

    【讨论】:

    • 我有一个定义了主键的表,它在模型中也被标记为[Key],我继续在你的答案和dbModelBuilder.Entity&lt;MyTable&gt;().ToTable("MyTable").Properties(e =&gt; e.ID); 中添加了前两行,但仍然没有喜悦.很高兴它对你有用,但听起来像是一个独特的情况。
    • 对我来说,修复我的代码的是复数行。一切都会按照正确的方式进行,包括 sql 流量,但没有结果,也没有首先更改代码(但仍然“成功”和播种)。我最初看到复数表的一些错误,并认为当错误消失时它们已修复。然而,当我运行 add-migration 并将上面的行添加到我的 dbcontext 并看到例如RenameTable(name: "dbo.Countries", newName: "Country"); 我知道这是解决办法。我只需要将其清空并使用该空迁移运行“更新数据库”。非常感谢!
    【解决方案3】:

    创建一个局部变量并为其分配您要检查的值。

    这将让您检查它,因为调试器不必担心访问该属性是否会干扰您的应用程序,因为它在将其分配给局部变量时已经访问了它。

    【讨论】:

      【解决方案4】:

      我发现一个名为“How to: Refresh Watch Values”的 MSDN 页面对此进行了解释:

      当您在调试器中评估表达式时,两个刷新图标之一可能会出现在“值”列中。一个刷新图标是一个包含两个箭头的圆圈,两个箭头朝相反的方向旋转。另一个是包含两条类似螺纹的波浪线的圆圈。

      ...

      如果出现两个线程,则表示由于潜在的跨线程依赖关系而未计算表达式。跨线程依赖意味着评估代码需要应用程序中的其他线程临时运行。 当您处于中断模式时,应用程序中的所有线程通常都会停止。允许其他线程临时运行会对程序的状态产生意想不到的影响,并导致调试器忽略断点等事件。

      如果有人能给我一个更好的解释,我仍然想要。这没有回答的问题包括:什么样的评估需要所有线程都运行?调试器如何识别这种情况?当您单击线程刷新图标时究竟会发生什么?

      编辑:我想我在检查Lazy&lt;T&gt; 下的ILSpy 时偶然发现了答案(出于完全不同的原因)。 Value 属性的 getter 调用了 Debugger.NotifyOfCrossThreadDependency()。 MSDN 有这样的说法:

      [...] 执行函数评估通常需要冻结除执行评估的线程之外的所有线程。如果函数评估需要在多个线程上执行,就像在远程场景中可能发生的那样,评估将阻塞。 NotifyOfCrossThreadDependency 通知通知调试器它必须释放线程或中止函数评估。

      所以基本上,为了防止您尝试评估某个表达式而 Visual Studio 只挂起 30 秒然后通知您“函数评估已超时”的烦人情况,代码有机会通知调试器它必须解冻其他线程才能使评估成功,否则评估将永远阻塞。

      由于运行其他线程可能会中断您的调试会话,通常当您评估一个表达式时,所有其他线程都保持冻结状态,调试器不会自动继续并在让您跳入兔子洞之前警告您。

      【讨论】:

        【解决方案5】:

        我的猜测是调试器试图通过为您加载属性来避免影响应用程序状态。

        您必须记住,延迟加载仅在您引用/访问属性时发生。

        现在,一般来说,您不希望调试影响应用程序的状态,否则将无法准确表示应用程序的状态应该是什么(考虑多线程应用程序和调试 )

        看看Heisenbug

        【讨论】:

        • 是的,我明白这一点,但是调试器会给出不同的警告(我已经看到过):这个表达式会导致副作用,不会被评估,然后您可以单击带有刷新图标的圆形按钮以强制评估。就我而言,调试器的消息说的很不一样。
        • @Cpfohl,请参阅我的答案的粗体文本。副作用可能是跨线程依赖的一个例子,但不是规则。我仍在寻找彻底、深入的解释。
        猜你喜欢
        • 2020-08-19
        • 2019-10-15
        • 2013-11-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多