单线程应用程序显示行为状态,如行为

时间:2010-09-21 08:04:31

标签: c# .net xml race-condition

我有一个大的(~40mb)XML数据集合,分成许多文件格式不正确,所以我合并它们,添加一个根节点并在XmlDocument中加载所有xml。它基本上是3种不同类型的列表,可以通过几种不同的方式嵌套。此示例应显示大多数情况:

<Root>
  <A>
    <A>
      <A></A>
      <A></A>
    </A>
  </A>
  <A />
  <B>
    <A>
      <A>
        <A></A>
        <A></A>
      </A>
    </A>
  </B>
  <C />
</Root>

通过在XmlDocument//A//B//C)上使用XPath表达式来分隔所有A,B和C节点,将生成的节点集转换为数据表并在Datagridview中分别显示每个节点类型的所有节点的列表。这很好。

但是现在我面对的是一个更大的文件,只要我加载它,它就会显示我只有4行。然后我在实际XmlDocument.SelectNodes发生的行添加了一个断点,并检查了结果NodeSet。它向我展示了大约25,000个条目。继续加载程序并呐喊后,我的所有25k行都显示出来。我再试一次,我可以重现它。如果我手动跨步XmlDocument.SelectNodes,它的工作原理。如果我不打破那里,它不会。我不会在我的应用程序中生成单个线程。

我如何进一步调试?要找什么?我遇到过像jsch(ssh)这样的多线程库的这种行为,但我不知道为什么在我的情况下会发生这种情况。

非常感谢!

// class XmlToDataTable:
private DataTable CreateTable(NamedXPath logType,
                              List<XmlColumn> columns,
                              ITableCreator tableCreator)
{
    // I have to break here -->
    XmlNodeList xmlNodeList = logFile.GetEntries(logType);
    // <-- I have to break here

    DataTable dataTable = tableCreator.CreateTableLayout(columns);
    foreach (XmlNode xmlNode in xmlNodeList)
    {
        DataRow row = dataTable.NewRow();
        tableCreator.PopulateRow(xmlNode, row, columns);
        dataTable.Rows.Add(row);
    }
    return dataTable;
}

// class Logfile:
public XmlNodeList GetEntries(NamedXPath e)
{
    return (_xmlDocument != null && _xmlDocument.HasChildNodes)
                         ? _xmlDocument.SelectNodes(e.XPath)
                         : new XmlNullObjectNodeList();
}
// _xmlDocument gets loaded here after reading all xml fragments into a string
// (ugly, i know. the  // ugly! comment reminds me about that ;))
private void CreateXmlDoc()
{
    _xmlDocument = new XmlDocument();
    _xmlDocument.LoadXml(OPEN_ROOT_ELEMENT + _xmlString +
                             CLOSE_ROOT_ELEMENT);
    if (DataChanged != null)
        DataChanged(this, new EventArgs());
}

// class NamedXPath:
public abstract class NamedXPath
{
    private readonly String _name;
    private readonly String _xPath;
    protected NamedXPath(string name, string xPath)
    {
        _name = name;
        _xPath = xPath;
    }

    public string Name
    {
        get { return _name; }
    }

    public string XPath
    {
        get { return _xPath; }
    }
}

2 个答案:

答案 0 :(得分:1)

不是先在代码中直接使用XPath,而是使用sketchPath这样的工具来使我的XPath正确。您可以加载原始XML或使用原始XML的子集。

使用XPath和XML来查看在代码中使用xpath之前是否选择了预期的节点。

答案 1 :(得分:0)

好的,解决了。 tableCreator是我的策略模式的一部分,它会影响表的构建方式。在某个实现中,我做了类似这样的事情:

XmlNode xn = xmlDocument.SelectSingleNode(fancyXPath);
// if a node has ancestors, then its a linked list:
// <a><a><a></a></a></a>
if(xn.SelectSingleNode("a") != null)
    xn.SelectSingleNode("a").InnerText = "<IDs of linked list items CSV like here>";

这意味着我用一些文本替换xml链表的一部分并丢失那里的嵌套项。 如果此更改不会影响原始XmlDocument,则找到此错误不会有问题。即便如此,调试它也不应该太难。是什么让我的程序表现不同取决于我是否休息似乎如下:

  

返回值:   第一个XmlNode   匹配XPath查询,如果不匹配,则返回null   找到匹配节点。 XmlNode   不应该被期望连接   “直播”到XML文档。那是,   XML中出现的更改   文件可能不会出现在   XmlNode,反之亦然。 (API   XmlNode.SelectNodes())

的描述

如果我在那里中断,更改将被写回原始的XmlDocument,如果我没有中断,则不会写回。无法真正向我自己解释,但如果没有XmlNode的变化,一切正常。

编辑: 现在我非常肯定:我的手表中有XmlNodeList.Count。这意味着,每次我调试时,VS都会调用属性Count,它不仅会返回一个数字,而是调用ReadUntil(int),刷新内部列表:

internal int ReadUntil(int index)
{
    int count = this.list.Count;
    while (!this.done && (count <= index))
    {
        if (this.nodeIterator.MoveNext())
        {
            XmlNode item = this.GetNode(this.nodeIterator.Current);
            if (item != null)
            {
                this.list.Add(item);
                count++;
            }
        }
        else
        {
            this.done = true;
            return count;
        }
    }
    return count;
}

这可能导致了这种奇怪的行为。