最佳输出字典

时间:2012-03-28 18:46:05

标签: c# performance dictionary disk-io

我有4个dictionarys,包含800k字符串,200到6000个字符。 当我把它加载到内存中它占用大约11演出的内存。 我需要2分钟来解析数据,2分钟才能输出数据。 无论如何输出数据比我下面使用的更快? 我只获得每秒20-31 MB的磁盘IO,我知道硬盘可以做800ish

var hash1 = new Dictionary<int, Dictionary<string, string>>(f.Count + 2);
var hash2 = new Dictionary<int, Dictionary<string, string>>(f.Count + 2);
var hash3 = new Dictionary<int, Dictionary<string, string>>(f.Count + 2);
var hash4 = new Dictionary<int, Dictionary<string, string>>(f.Count + 2);
....
foreach (var me in mswithfilenames)
{
    filename = me.Key.ToString();
    string filenamef = filename + "index1";
    string filenameq = filename + "index2";
    string filenamefq = filename + "index3";
    string filenameqq = filename + "index4";

    StreamWriter sw = File.AppendText(filenamef);
    StreamWriter sw2 = File.AppendText(filenameq);
    StreamWriter swq = File.AppendText(filenamefq);
    StreamWriter sw2q = File.AppendText(filenameqq);

    for (i = 0; i <= totalinhash; i++)
    {
        if (hashs1[i].ContainsKey(filenamef))
        {
            sw.Write(hashs1[i][filenamef]);
        }
        if (hashs2[i].ContainsKey(filenameq))
        {
            sw2.Write(hashs2[i][filenameq]);
        }
        if (hashs3[i].ContainsKey(filenamefastaq))
        {
            swq.Write(hash4[i][filenamefastaq]);
        }

        if (hash4[i].ContainsKey(filenameqq))
        {
            sw2q.Write(hash4[i][filenameqq]);
        }
    }

    sw.Close();
    sw2.Close();
    sw3.Close();
    sw4.Close();
    swq.Close();
    sw2q.Close();
}

4 个答案:

答案 0 :(得分:3)

你有什么衡量标准吗?听起来你有大量的数据需要读写 - 所以第一步是为你的磁盘子系统建立绝对基线,读取/写入大量数据的速度。简单读取文件,然后写入您预期的大致数据量的新文件,将显示您可以在多大程度上优化它。

您可能会认为您的代码本身不会花费太多时间来阅读/写作。

答案 1 :(得分:2)

最昂贵的部分是I / O.这个循环:

for (i = 0; i <= totalinhash; i++)
{
    if (hashs1[i].ContainsKey(filenamef))
    {
        sw.Write(hashs1[i][filenamef]);
    }
    if (hashs2[i].ContainsKey(filenameq))
    {
        sw2.Write(hashs2[i][filenameq]);
    }
    ...
}

在不同文件之间交替。这可能会导致一些额外的头部移动,并且会创建碎片文件(减慢将来对这些文件的操作)。

我会用:

for (i = 0; i <= totalinhash; i++)
{
    if (hashs1[i].ContainsKey(filenamef))
    {
        sw.Write(hashs1[i][filenamef]);
    }
}

for (i = 0; i <= totalinhash; i++)
{
    if (hashs2[i].ContainsKey(filenameq))
    {
        sw2.Write(hashs2[i][filenameq]);
    }
}
...

但当然你应该衡量这一点。例如,仅在机械磁盘上​​,它对SSD没有太大影响。

答案 2 :(得分:1)

你能有一个Dictionary<int, Dictionary<string, myCustomDataHolder>>而不是四个独立的并行Dictionary<int, Dictionary<string, string>吗?它不仅应该减少占用的空间很多,而且意味着字典查找的1/4。

根据你的问题,字典是否完全平行还不是很清楚,但对我来说似乎已经足够了。

答案 3 :(得分:0)

我想补充一下

if (hashs1[i].ContainsKey(filenamef))
{
   sw.Write(hashs1[i][filenamef]);
}

进行2次哈希表访问。一个用于包含密钥,一个用于实际访问。许多字典访问可以加起来,因此您可以使用字典tryGetValue方法将这些访问减半。这将把这两个调用合二为一。我可以解释一下这是如何工作的,但这比我做得更好:http://www.dotnetperls.com/trygetvalue