我的 C#应用程序读取以下结构的XML-File 。 150mb文件中有大约250,000个单词。
<word>
<name>kick</name>
<id>485</id>
<rels>12:4;4256:3;754:3;1452:2;86:2;125:2;</rels>
</word>
我想将XML文件读入字典。这些是我阅读课的一些班级成员。
private XmlReader Reader;
public string CurrentWordName;
public int CurrentWordId;
public Dictionary<KeyValuePair<int, int>, int> CurrentRelations;
这是我阅读课的主要方法。它只读取文件中的下一个单词并获取name
,id
,并将关系存储到字典中。
CurrentWordId = -1;
CurrentWordName = "";
CurrentRelations = new Dictionary<KeyValuePair<int, int>, int>();
while(Reader.Read())
if(Reader.NodeType == XmlNodeType.Element & Reader.Name == "word")
{
while (Reader.Read())
if (Reader.NodeType == XmlNodeType.Element & Reader.Name == "name")
{
XElement Title = XElement.ReadFrom(Reader) as XElement;
CurrentWordName = Title.Value;
break;
}
while (Reader.Read())
if (Reader.NodeType == XmlNodeType.Element & Reader.Name == "id")
{
XElement Identifier = XElement.ReadFrom(Reader) as XElement;
CurrentWordId = Convert.ToInt32(Identifier.Value);
break;
}
while(Reader.Read())
if (Reader.NodeType == XmlNodeType.Element & Reader.Name == "rels")
{
XElement Text = XElement.ReadFrom(Reader) as XElement;
string[] RelationStrings = Text.Value.Split(';');
foreach (string RelationString in RelationStrings)
{
string[] RelationsStringSplit = RelationString.Split(':');
if (RelationsStringSplit.Length == 2)
CurrentRelations.Add(new KeyValuePair<int,int>(CurrentWordId,Convert.ToInt32(RelationsStringSplit[0])), Convert.ToInt32(RelationsStringSplit[1]));
}
break;
}
break;
}
if (CurrentRelations.Count < 1 || CurrentWordId == -1 || CurrentWordName == "")
return false;
else
return true;
我的Windows窗体有一个backgroundWorker
来阅读所有单词。
private void bgReader_DoWork(object sender, DoWorkEventArgs e)
{
ReadXML Reader = new ReadXML(tBOpenFile.Text);
Words = new Dictionary<int, string>();
Dictionary<KeyValuePair<int, int>, int> ReadedRelations = new Dictionary<KeyValuePair<int, int>, int>();
// reading
while(Reader.ReadNextWord())
{
Words.Add(Reader.CurrentWordId, Reader.CurrentWordName);
foreach (KeyValuePair<KeyValuePair<int, int>, int> CurrentRelation in Reader.CurrentRelations)
{
ReadedRelations.Add(new KeyValuePair<int, int>(CurrentRelation.Key.Key, CurrentRelation.Key.Value), CurrentRelation.Value);
}
}
通过调试,我注意到应用程序启动非常快,并且随着时间的推移而变慢。
我无法解释这种行为!但我确信XML文件中的单词平均大小相同。也许Add()
- 方法因字典长度变慢。
如何加快申请速度?
答案 0 :(得分:3)
编辑:好的,既然我已经运行了代码,我相信这就是问题:
foreach (KeyValuePair<KeyValuePair<int, int>, int> CurrentRelation in
Reader.CurrentRelations)
{
ReadedRelations.Add(new KeyValuePair<int, int>(CurrentRelation.Key.Key,
CurrentRelation.Key.Value), CurrentRelation.Value);
}
如果没有那个循环,它会更快地 ...这让我怀疑你从XML读取的事实实际上是一个红色的鲱鱼。
我怀疑问题是KeyValuePair<,>
没有覆盖Equals
和GetHashCode
。我相信,如果您创建自己的RelationKey
值类型,其中包含两个int
值并覆盖GetHashCode
和Equals
(以及实施IEquatable<RelationKey>
),那么它将是快得多。
或者,您可以始终使用long
来存储两个int
值 - 这有点像黑客,但它会很好用。我现在无法测试,但是当我有更多时间时,我会试一试。
即使只是将你的循环改为:
foreach (var relation in Reader.CurrentRelations)
{
ReadedRelations.Add(relation.Key, relation.Value);
}
会更简单,效率更高......
编辑:这是RelationKey
结构的示例。只需将所有KeyValuePair<int, int>
替换为RelationKey
,并使用Source
和Target
属性代替Key
和Value
:
public struct RelationKey : IEquatable<RelationKey>
{
private readonly int source;
private readonly int target;
public int Source { get { return source; } }
public int Target { get { return target; } }
public RelationKey(int source, int target)
{
this.source = source;
this.target = target;
}
public override bool Equals(object obj)
{
if (!(obj is RelationKey))
{
return false;
}
return Equals((RelationKey)obj);
}
public override int GetHashCode()
{
return source * 31 + target;
}
public bool Equals(RelationKey other)
{
return source == other.source && target == other.target;
}
}