如何加快二进制读/写

时间:2018-10-29 02:18:05

标签: c# io binaryfiles binary-data

我有这个代码

//N = 32;
//B = 27;
using (FileStream fs = File.Open(path, FileMode.OpenOrCreate, FileAccess.ReadWrite))
{
    using (BinaryReader br = new BinaryReader(fs))
    {
        using (BinaryWriter bw = new BinaryWriter(fs))
        {
            for (int k = B; k < N; ++k)
            {
                Console.WriteLine(k);
                long pt = 0;
                long j = 1L << k;
                for (long i = 0; i < (1L << (N - 1)); ++i)
                {
                    long b1;
                    long b2;

                    br.BaseStream.Seek(8 * (pt), SeekOrigin.Begin);
                    b1 = br.ReadInt64();
                    br.BaseStream.Seek(8 * (j - 1), SeekOrigin.Current);
                    b2 = br.ReadInt64();

                    long t1 = b1 + b2;
                    long t2 = b1 - b2;

                    bw.BaseStream.Seek(8 * (pt), SeekOrigin.Begin);
                    bw.Write(t1);
                    bw.BaseStream.Seek(8 * (j - 1), SeekOrigin.Current);
                    bw.Write(t2);

                    pt += 1;
                    if ((pt & (j - 1L)) == 0)
                    {
                        pt += j;
                    }
                    if ((i % 100000) == 0) Console.WriteLine(i);
                }
            }
        }
    }
}

发生的事情是,该程序从一个很大的(17 GB)文件中的不同位置读取两个long,然后将它们相加/相减,然后在相同位置重写新值。

据我所知,读取数据的最有效方法是将大块读入缓冲区,然后使用该缓冲区。但是,这种方法在这里行不通,因为基于 pt j 的值,它可能是从文件的开头和结尾读取的,当然我无法将所有17 GB的内存都存储在内存中。

if ((i % 100000) == 0) Console.WriteLine(i);

用于调试,在我的计算机上它们之间大约需要2秒钟。我需要这个要快得多。我关注的论文说,在此循环中,它们的实现花费了不到30分钟的时间。有没有更快的选择可以快速读取大量数字数据?

2 个答案:

答案 0 :(得分:2)

这本身并不是一个答案。但是,它应该给您一些思路,让您知道如何具体地加快速度

乍一看,这可分为概率,并行度和卡盘大小。

如果很有可能在较大的块中找到下一个/写入的读取,则较大的块大小将提高性能。反过来,它也不必继续扫描磁盘。

如果您使用的是 SSD ,则可能会以比可能使用的默认4k块更高的性能(一次)加载Mb级。

此外,似乎可以将其分解为并行工作负载...虽然目前尚不清楚一开始需要进行哪些修改。

但是,如果您真的想要这么快

  • 去购买自己的32公羊
  • 创建一个继承的Stream类,甚至最好是一个自定义类
  • 将整个数据集加载到内存中,分成大约一个演出的大块数组。
  • 使用直接指针访问
  • 使用平行工作负荷

如果您可以这样做(这是推测性的),则可能可以更快地加快许多因素的速度。而且要花费数百美元的内存和一天的编码时间。

很棒的评论来自 @NPras

  

除了自己管理RAM缓存/分块外,您还可以   想看一下memory-mapped file的概念,并让操作系统   为您管理

并且来自Managing Memory-Mapped Files

enter image description here

答案 1 :(得分:0)

如果我理解正确,那么结果将写回到您刚刚读取的位置。

因此,如果您颠倒写入顺序,则第一次写入将是您最后一次读取的位置。

这将减少寻道时间。

此外,这意味着下一个读取也将与另一个写入相邻,从而再次减少了查找时间。

现在,“ i”上的主循环显然很长,但我认为您可以:

  • 将其拆分为中等大小的块(可能只需要64M左右)
  • 进行全部读取
  • 进行第二次读取
  • 对两个块进行内存中计算
  • 写出来