我正尝试编写大量到我 SSD (固态驱动器) 上的数据。并通过了大量我的意思是 80 GB。

我浏览 web 的解决方案,但是的最好的我想到的是︰

#include <fstream>
using namespace std;
const unsigned long long size = 64ULL*1024ULL*1024ULL;
unsigned long long a[size];
int main()
{
    fstream myfile;
    myfile = fstream("file.binary", ios::out | ios::binary);
    //Here would be some error handling
    for(int i = 0; i < 32; ++i){
        //Some calculations to fill a[]
        myfile.write((char*)&a,size*sizeof(unsigned long long));
    }
    myfile.close();
}

使用 Visual Studio 2010 和完整的优化和运行这个程序 maxes 出周围 20 MB/s 的 windows7 作为下编译。什么真的厌烦我时,Windows 可以将文件从其他 SSD 到此 SSD 在某处之间 150 MB/s 和 200 MB/s。因此至少 7 次速度更快。这就是为什么我认为我不应该能够越快越好。

任何想法如何我可以提高我的写作速度?

2012-07-19 15:18:23
问题评论:

计时结果未排除进行填充 [] 您计算所花费的时间吗?

我实际上已经完成此任务之前。使用简单fwrite()可能得到约 80%的峰值写入速度。只有FILE_FLAG_NO_BUFFERING了我以往任何时候都能获得最大速度。

使用测试这段代码不编译,所以这不是代码。复制和粘贴确切代码中您使用,以便我们可以与其他方法进行比较。

我不确定它是公平比较 SSD 到 SSD 复制到您文件 writeing。它也可能是 SSD 到 SSD 上较低的级别上,避免了 c + + 库中,或使用直接内存访问 (DMA) 工作。复制的内容不是任意值写入随机访问文件相同。

@IgorF.︰ 这是只是错误的推理;它是非常公平的比较 (如果没有其他的而文件写入)。在 Windows 中的某个驱动器之间复制是刚读写;没有任何别致/复杂/不同开始往上下方。

回答:

这没有作业︰

#include <stdio.h>
const unsigned long long size = 8ULL*1024ULL*1024ULL;
unsigned long long a[size];

int main()
{
    FILE* pFile;
    pFile = fopen("file.binary", "wb");
    for (unsigned long long j = 0; j < 1024; ++j){
        //Some calculations to fill a[]
        fwrite(a, 1, size*sizeof(unsigned long long), pFile);
    }
    fclose(pFile);
    return 0;
}

我只是计时 36 秒,它主要是关于 220MB/s 8GB,我想出我 SSD 的 maxes。此外值得注意的是,我帖子的开头的代码使用一个内核 100%,而这段代码只使用 2-5%。

感谢所有人。

+ 1 是,这是我尝试的第一件事。FILE*是比流速度更快。我不会期望焕然一新因为它"应了"被 I/O 绑定吗。

我们可以断定 C 样式 I/O 是 (异常) 比 c + + 流快得多吗?

@SChepurin︰ 如果您正在 pedantic,不可能。如果您是可行的可能是。:)

您能详细解释 (对于像我这样的 c + + dunce) 这两种方法之间的差异,以及为何此人工作太多比原来快吗?

不会预先计算ios::sync_with_stdio(false);使具有流的代码有任何区别吗?我只是好奇多大区别,没有之间使用下面这行并不是这样,但我没有足够快的速度的磁盘,以检查极端情况。并且,如果没有任何真正的差异。

请尝试以下操作,按顺序︰

  • 较小的缓冲区大小。写入一次 ~ 2 MiB 可能一个不错的起点。在我最后一次的便携式计算机,~ 512 KiB 是最擅长的领域,但我还没有对测试我 SSD 上。

    注意︰我已经注意到非常大的缓冲区,往往会降低性能。我已经注意到与使用 16 MiB 的缓冲区,而不之前的 512 KiB 缓冲区的速度损失。

  • 使用打开该文件,然后使用_write _open(或_topen如果您希望在 Windows 更正)。这将可能避免大量的缓冲,但不一定到。

  • 使用 Windows 特定功能,如CreateFileWriteFile这可以避免在标准库中任何缓冲。

检查任何基准结果在线发布。您需要 4 kB 写入队列深度为 32 的详细信息,或否则 512k 或高写入操作以获取任何种类的相当不错的吞吐量。

@BenVoigt: yup 的关联与我说 512 KiB 我最擅长的领域。:)

是的。从我的经验,较小的缓冲区大小是通常是最佳的。例外情况是当您使用FILE_FLAG_NO_BUFFERING -更大的缓冲区倾向会更好。因为我认为FILE_FLAG_NO_BUFFERING是差不多 DMA。

我看到 std::stream/文件/设备之间没有区别。之间的缓冲非缓冲。

此外请注意︰

  • SSD 驱动器"往往会"降低 (较低传输率) 因为它们填满。
  • SSD 驱动器"往往会"降低 (较低传输率) 一些旧 (由于非工作位)。

我能看到在 63 secondds 中运行的代码。
这样的传输速率︰ 260 M/s (我 SSD 外观比您会稍微快一些)。

64 * 1024 * 1024 * 8 /*sizeof(unsigned long long) */ * 32 /*Chunks*/

= 16G
= 16G/63 = 260M/s

通过将移到文件 * 从 std::fstream 得到没有得到提高。

#include <stdio.h>

using namespace std;

int main()
{

    FILE* stream = fopen("binary", "w");

    for(int loop=0;loop < 32;++loop)
    {
         fwrite(a, sizeof(unsigned long long), size, stream);
    }
    fclose(stream);

}

因此,c + + 流正在为基础快速将允许库。

但我认为这是不公平的比较建立在最前面的操作系统应用程序操作系统。应用程序可以做出任何假设 (它不会不知道驱动器 SSD),因此传输使用的操作系统的文件架。

当操作系统不需要做出任何假设。它可以告诉所涉及的驱动器的类型和用于传输数据的最佳方法。在这种情况下直接内存到内存传输。尝试编写将 80 G 从内存中的一个位置复制到另一个程序,看到的是速度。

编辑

我改变我的代码以使用较低级别的调用︰
ie 没有缓冲。

#include <fcntl.h>
#include <unistd.h>


const unsigned long long size = 64ULL*1024ULL*1024ULL;
unsigned long long a[size];
int main()
{
    int data = open("test", O_WRONLY | O_CREAT, 0777);
    for(int loop = 0; loop < 32; ++loop)
    {   
        write(data, a, size * sizeof(unsigned long long));
    }   
    close(data);
}

这使得没有 diffference。

注意︰ 如果有正常驱动器,您可能会看到上述两种方法之间的差异,我的驱动器是 SSD 驱动器。但像我预期的那样非缓冲和缓冲 (编写大块大于缓冲区的大小) 时并不重要。

编辑 2:

尝试了在 c + + 中复制文件的最快方法

int main()
{
    std::ifstream  input("input");
    std::ofstream  output("ouptut");

    output << input.rdbuf();
}

我没有 downvote,但缓冲区大小太小。做与 OP 使用相同的 512 MB 缓冲区并流与FILE* 90 MB/s 的 20 MB/s.

此外按照您的意愿 fwrite ((无符号长长),sizeof,大小,流);而不是 fwrite (一个,1,大小 * sizeof (无符号长长),pFile);为我提供了 220 MB/s 的 64 mb 每次写入的数据块。

@Mysticial︰ 它奇异的事情发生我的缓冲区大小使存在差异 (虽然我相信您)。缓冲区是有用,当您拥有大量小数据写入基础设备不困扰许多请求。但当您编写的大块缓冲区无需时写入/读取 (阻止设备) 上。这种数据应能直接传递给基础设备 (因此 by-passing 缓冲区)。但如果看到差异这将矛盾这并使我奇怪为什么,写实际上会使用缓冲区。

最好的解决办法是增加缓冲区大小,但要删除缓冲区,并使编写数据将直接传递给基础设备。

这不会更改,但我也是如此,它是不公平的比较。

请尝试使用 open()/write()/close() API 调用并输出缓冲区的大小进行试验。我的意思是不要不同时通过整个"多多的字节"缓冲区、 做了几个写操作 (例如,TotalNumBytes / OutBufferSize)。OutBufferSize 可以为 4096 个字节到兆字节。

另一个尝试-使用选择打开文件/CreateFile 并使用MSDN 本文关闭缓冲 (FILE_FLAG_NO_BUFFERING)。在 WriteFile() 上的此 MSDN 文章演示如何获取驱动器知道最佳的缓冲区大小的块大小。

不管怎样,std::ofstream 的包装,并那里可能在 I/O 操作上阻塞。请记住,遍历整个 N 千兆字节数组还需要一些时间。虽然您正在编写一个小的缓冲区,对缓存获取并运行更快。

无法使用FILE*相反,并且测量性能已获得了吗?两种选择是使用fwrite/write而不是fstream:

#include <stdio.h>

int main ()
{
  FILE * pFile;
  char buffer[] = { 'x' , 'y' , 'z' };
  pFile = fopen ( "myfile.bin" , "w+b" );
  fwrite (buffer , 1 , sizeof(buffer) , pFile );
  fclose (pFile);
  return 0;
}

如果您决定使用write,请尝试类似的代码︰

#include <unistd.h>
#include <fcntl.h>

int main(void)
{
    int filedesc = open("testfile.txt", O_WRONLY | O_APPEND);

    if (filedesc < 0) {
        return -1;
    }

    if (write(filedesc, "This will be output to testfile.txt
", 36) != 36) {
        write(2, "There was an error writing to testfile.txt
", 43);
        return -1;
    }

    return 0;
}

我还想建议您查看memory map这可能是您的答案。一次,我不得不处理 20 GB 文件以其他将其存储在数据库中,并作为甚至不打开该文件。因此,利用 moemory 映射解决方案。我这样做是在Python中通过。

实际上,使用相同的 512 MB 缓冲区的原始代码非常简单的FILE*等效获取全速运转。您当前的缓冲区规模太小。

@Mysticial,但这只是一个示例。

内容来源于Stack Overflow Writing a binary file in C++ very fast
请输入您的翻译

Writing a binary file in C++ very fast

确认取消