1

我有 4 个字典,其中包含 800k 字符串,包含 200 到 6000 个字符。当我将它加载到内存中时,它会占用大约 11 GB 的内存。解析数据需要 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

4 回答 4

3

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

您可能会觉得您的代码本身不会在读/写上花费太多时间。

于 2012-03-28T18:54:22.450 回答
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 产生太大影响,仅在机械磁盘上​​。

于 2012-03-28T19:56:12.470 回答
1

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

鉴于您的问题,尚不清楚字典是否完全平行,但对我来说似乎足够了。

于 2012-03-28T18:53:16.300 回答
0

我想补充一点

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

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

于 2012-05-17T22:40:42.410 回答