优化输出字典

本文关键字:字典 输出 优化 | 更新日期: 2023-09-27 18:29:13

我有4个字典,其中包含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();
}

优化输出字典

你测量了什么吗?听起来您有大量的数据要读和写,所以第一步是为您的磁盘子系统建立绝对的基线,以确定它读/写那么多数据的速度。简单地读取文件,然后向新文件写入您期望的大致数据量,这将显示您在优化它方面可以走多远

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

最昂贵的部分是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]);
    }
}
...

但你当然应该衡量一下。例如,它在固态硬盘上不会有太大区别,只在机械磁盘上。

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

考虑到你的问题,词典是否完全平行还不太清楚,但对我来说似乎已经足够了

我想添加

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

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