【问题标题】:Error in Parallel.ForEach - Object reference not set to an instance of an objectParallel.ForEach 中的错误 - 对象引用未设置为对象的实例
【发布时间】:2011-03-31 07:49:31
【问题描述】:

我有一个无法调试的奇怪问题。这是一个解析信息的委托:

Action<XElement, String> ParseXMLInfo = (s, t) =>
{
    using (var Ctx = new Entities())
    {
        var Records = s.Elements("record");
        Parallel.ForEach(
            ParallelEnumerable.Range(0, Records.Count()),
            u =>
            {
                var el = Records.ElementAt(u);
                try
                {
                    var NTR = new tbl_UserInfo();
                    NTR.first_name = el.Element("first_name").Value;
                    NTR.last_name = el.Element("last_name").Value;
                    Ctx.AddTotbl_UserInfo(NTR);
                }
                catch (Exception excp)
                {
                    Console.WriteLine(System.DateTime.Now + " " + excp.Message);
                }
            }
        );
        Ctx.SaveChanges();
    }
};

委托本身被调用两次,如下:

Parallel.Invoke(
    () =>
    {
        var XMLDoc_MaleInfo = XElement.Load("MaleNames.xml");
        Console.WriteLine("Fetching records from MaleNames.xml; starting at " + System.DateTime.Now);
        ParseXMLInfo(XMLDoc_MaleInfo, "male");
    },
    () =>
    {
        var XMLDoc_FemaleInfo = XElement.Load("FemaleNames.xml");
        Console.WriteLine("Fetching records from FemaleNames.xml; starting at " + System.DateTime.Now);
        ParseXMLInfo(XMLDoc_MaleInfo, "female");
    }
);

一切似乎都运行正常。特别是,委托的 Parallel.ForEach 部分运行时没有任何错误。但随后,代码在Ctx.SaveChanges () 行中断,并显示消息

对象引用未设置为对象的实例。

但是当我将鼠标悬停在Ctx(处于这种损坏状态)上时,Ctx 不会显示为null

谁能告诉我这是怎么回事?

【问题讨论】:

  • 您可以发布您的Entities 课程吗?我怀疑它不是线程安全的。而且您正在从多个线程对其进行写入。
  • @CodeInChaos Entities 类是在我添加 ADO.NET 实体数据模型时由 .NET 生成的。我没有修改系统本身为它生成的代码。如果你真的想要,我可以把整个文件贴出来,但是太长了。
  • @CodeInChaos 您可能正在做某事。当我注释掉“try”和“catch”行时,AttTotbl_UserInfo 出现以下错误:“Test.tbl_UserInfo 类型已被多次映射。”

标签: c# multithreading parallel.foreach


【解决方案1】:

认为应该是:

ParallelEnumerable.Range (0, Records.Count()-1)

【讨论】:

    【解决方案2】:

    好的,在浏览了 MSDN 文档之后,我现在似乎已经想出了至少一个解决方案。这是重构后的代码。

    Action<XElement, String> ParseXMLInfo = (s, t) => {
                var Records = s.Elements ("record");
                Parallel.ForEach (
                    ParallelEnumerable.Range (0, Records.Count ()),
                    () => new Testing_And_Benchmarking_Entities (),
                    (u, L, v) => {
                        var el = Records.ElementAt (u);
                        var NTR = new tbl_UserInfo ();
                        NTR.first_name = el.Element ("first_name").Value;
                        NTR.last_name = el.Element ("last_name").Value;
                        v.AddTotbl_UserInfo (NTR);
                        return v;
                    },
                    (v) => v.SaveChanges ()
                );
            };
            Parallel.Invoke (
                () => {
                    var XMLDoc_MaleInfo = XElement.Load ("MaleNames.xml");
                    Console.WriteLine ("Fetching records from MaleNames.xml; starting at " + System.DateTime.Now);
                    ParseXMLInfo (XMLDoc_MaleInfo, "male");
                },
                () => {
                    var XMLDoc_FemaleInfo = XElement.Load ("FemaleNames.xml");
                    Console.WriteLine ("Fetching records from MaleNames.xml; starting at " + System.DateTime.Now);
                    ParseXMLInfo (XMLDoc_FemaleInfo, "female");
                }
            );
    

    我不得不使用不同的 Parallel.ForEach 重载签名。在这个重载中,与前面示例中的 Ctx 变量等效(本示例中的“v”,请原谅隐晦的变量名称)不共享。这样就避免了错误。

    如果我的解决方案是唯一的解决方案,或者是否有更好、更惯用的 C# 解决方案,我仍然希望有知识渊博的人发表评论。

    【讨论】:

      猜你喜欢
      • 2011-07-09
      • 2012-08-31
      • 2011-11-21
      • 2012-10-01
      • 1970-01-01
      • 1970-01-01
      • 2022-08-18
      相关资源
      最近更新 更多