我搜索一个复制文件(二进制或文本)的好方法.我写过几个样本,每个人都在工作.但我想听听经验丰富的程序员的意见.
我错过了很好的例子并搜索了一种适用于C++的方法.
ANSI-C-WAY
#include <iostream>
#include <cstdio> // fopen, fclose, fread, fwrite, BUFSIZ
#include <ctime>
using namespace std;
int main() {
clock_t start, end;
start = clock();
// BUFSIZE default is 8192 bytes
// BUFSIZE of 1 means one chareter at time
// good values should fit to blocksize, like 1024 or 4096
// higher values reduce number of system calls
// size_t BUFFER_SIZE = 4096;
char buf[BUFSIZ];
size_t size;
FILE* source = fopen("from.ogv", "rb");
FILE* dest = fopen("to.ogv", "wb"); …Run Code Online (Sandbox Code Playgroud) POSIX环境提供至少两种访问文件的方法.有标准的系统调用open(),read(),write(),和朋友,但也有使用的选项mmap(),将文件映射到虚拟内存.
何时优先使用一个而不是另一个?它们各自的优势是什么,包括两个接口?
每当我提到C++标准库iostream的慢性能时,我都会遇到一阵难以置信的风潮.然而,我有剖析器结果显示在iostream库代码中花费了大量时间(完全编译器优化),并且从iostream切换到特定于操作系统的I/O API和自定义缓冲区管理确实提供了一个数量级的改进.
C++标准库做了多少额外工作,标准是否需要它,它在实践中是否有用?或者有些编译器提供了与手动缓冲区管理竞争的iostream实现吗?
为了解决问题,我编写了几个简短的程序来练习iostreams内部缓冲:
ostringstream http://ideone.com/2PPYwchar[]缓冲区http://ideone.com/Ni5ctvector<char>使用http://ideone.com/Mj2Fi将二进制数据放入其中back_inserter vector<char>简单的迭代器http://ideone.com/9iitvstringbuf http://ideone.com/qc9QAvector<char>简单的迭代器加边界检查http://ideone.com/YyrKy请注意,ostringstream和stringbuf版本运行的迭代次数较少,因为它们的速度要慢得多.
在ideone上,它ostringstream比std:copy+ back_inserter+ 慢大约3倍std::vector,比memcpy原始缓冲区慢大约15倍.当我将实际应用程序切换到自定义缓冲时,这与前后分析一致.
这些都是内存缓冲区,因此iostream的缓慢不能归咎于缓慢的磁盘I/O,过多的刷新,与stdio的同步,或者人们用来解释C++标准库观察到的缓慢的任何其他事情iostream的.
很高兴看到其他系统上的基准测试和常见实现的评论(例如gcc的libc ++,Visual C++,Intel C++)以及标准规定了多少开销.
许多人都正确地指出,iostream更常用于格式化输出.但是,它们也是C++标准提供的二进制文件访问的唯一现代API.但是对内部缓冲进行性能测试的真正原因适用于典型的格式化I/O:如果iostreams无法保持磁盘控制器提供原始数据,那么当他们负责格式化时,他们怎么可能跟上呢?
所有这些都是outer(k)循环的每次迭代.
在ideone上(gcc-4.3.4,未知的操作系统和硬件):
ostringstream:53毫秒stringbuf:27毫秒vector<char>并且back_inserter:17.6毫秒vector<char> 与普通迭代器:10.6毫秒vector<char> 迭代器和边界检查:11.4 mschar[]:3.7毫秒在我的笔记本电脑上(Visual C++ 2010 x86,cl …
我正在研究一个简单的解析器,在进行分析时我发现瓶颈在...文件读取!我摘录了非常简单的测试来比较的性能fstreams和FILE*读取数据的大斑点时:
#include <stdio.h>
#include <chrono>
#include <fstream>
#include <iostream>
#include <functional>
void measure(const std::string& test, std::function<void()> function)
{
auto start_time = std::chrono::high_resolution_clock::now();
function();
auto duration = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock::now() - start_time);
std::cout<<test<<" "<<static_cast<double>(duration.count()) * 0.000001<<" ms"<<std::endl;
}
#define BUFFER_SIZE (1024 * 1024 * 1024)
int main(int argc, const char * argv[])
{
auto buffer = new char[BUFFER_SIZE];
memset(buffer, 123, BUFFER_SIZE);
measure("FILE* write", [buffer]()
{
FILE* file = fopen("test_file_write", "wb");
fwrite(buffer, 1, BUFFER_SIZE, file);
fclose(file);
});
measure("FILE* read", [buffer]() …Run Code Online (Sandbox Code Playgroud) 什么限制了内存映射文件的大小?我知道它不能超过最大的连续未分配地址空间块,并且应该有足够的可用磁盘空间.但还有其他限制吗?
我一直听说C++文件I/O操作比C风格I/O慢得多.但我没有找到任何实际的参考文件,因为它们实际上有多慢,所以我决定在我的机器上测试它(Ubuntu 12.04,GCC 4.6.3,ext4分区格式).
首先,我在磁盘中写了一个~900MB的文件.
C++(ofstream):163s
ofstream file("test.txt");
for(register int i = 0; i < 100000000; i++)
file << i << endl;
Run Code Online (Sandbox Code Playgroud)
C(fprintf):12s
FILE *fp = fopen("test.txt", "w");
for(register int i = 0; i < 100000000; i++)
fprintf(fp, "%d\n", i);
Run Code Online (Sandbox Code Playgroud)
我期待这样的输出,它表明在C++ C中写入文件要慢得多.然后我使用C和C++ I/O读取相同的文件.让我感到惊讶的是,从文件中读取时,性能几乎没有差异.
C++(ifstream):12s
int n;
ifstream file("test.txt");
for(register int i = 0; i < 100000000; i++)
file >> n;
Run Code Online (Sandbox Code Playgroud)
C(fscanf):12s
FILE *fp = fopen("test.txt", "r");
for(register int i = 0; i < …Run Code Online (Sandbox Code Playgroud) 使用下面的程序我尝试测试我可以用多快的速度写入磁盘std::ofstream.
在写入1 GiB文件时,我达到大约300 MiB/s.
但是,使用该cp命令的简单文件复制速度至少快两倍.
我的程序是否达到了硬件限制,还是可以更快?
#include <chrono>
#include <iostream>
#include <fstream>
char payload[1000 * 1000]; // 1 MB
void test(int MB)
{
// Configure buffer
char buffer[32 * 1000];
std::ofstream of("test.file");
of.rdbuf()->pubsetbuf(buffer, sizeof(buffer));
auto start_time = std::chrono::steady_clock::now();
// Write a total of 1 GB
for (auto i = 0; i != MB; ++i)
{
of.write(payload, sizeof(payload));
}
double elapsed_ns = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::steady_clock::now() - start_time).count();
double megabytes_per_ns = 1e3 / elapsed_ns;
double megabytes_per_s = 1e9 * megabytes_per_ns; …Run Code Online (Sandbox Code Playgroud) 我需要编写一个程序,它将在输出文件中写入许多字符.我的程序还需要编写换行符以便更好地格式化.我理解ofstream是一个缓冲流,如果我们使用缓冲流文件io,我们获得了性能.但是,如果我们使用std::endl输出将被刷新,并且由于缓冲输出,我们将失去任何潜在的性能增益.
我想如果我使用'\n'新行,输出将只在我们将要刷新时刷新std::endl.它是否正确?是否有任何技巧可用于在文件输出期间获得性能提升?
注意:我想在文件写入操作完成时刷新缓冲输出.我认为通过这种方式,我可以最小化文件I/O,从而获得性能.
在不使用iostream接口的情况下,存储C++ 11随机生成器状态的最佳方法是什么.我想像这里列出的第一个替代品那样做[1]?但是,此方法要求对象包含PRNG状态且仅包含PRNG状态.在partucular,它如果实现使用PIMPL模式失败(至少这是有可能重新加载状态,而不是用坏的数据加载它,当应用程序崩溃),或有与没有的PRNG对象相关联的多个状态变量与生成的序列有关.
对象的大小是实现定义的:
g++ (tdm64-1) 4.7.1sizeof(std::mt19937)==2504但是给了Ideone http://ideone.com/41vY5j给出2500我缺少像这样的成员函数
size_t state_size();const size_t* get_state() const;void set_state(size_t n_elems,const size_t* state_new);(1)应返回随机生成器状态数组的大小
(2)应返回指向状态数组的指针.指针由PRNG管理.
(3)应从std::min(n_elems,state_size())state_new指向的缓冲区中复制缓冲区
这种接口允许更灵活的状态操作.或者是否有任何PRNG:s的状态不能表示为无符号整数数组?
现在我在内存中每秒获得大约3.6GB的数据,我需要不断地在我的SSD上写它们.我使用CrystalDiskMark来测试我的SSD的写入速度,它几乎是每秒6GB,所以我认为这项工作不应该那么难.
![我的SSD测试结果] [1]:
[1] https://plus.google.com/u/0/photos/photo/106876803948041178149/6649598887699308850?authkey=CNbb5KjF8-jxJQ "测试结果":
我的电脑是Windows 10,使用Visual Studio 2017社区.
我找到了这个问题,并尝试了最高的投票答案.不幸的是,他的option_2的写入速度仅为1s/GB,远远低于CrystalDiskMark所测试的速度.然后我尝试了内存映射,这次写入变得更快,大约630ms/GB,但仍然慢得多.然后我尝试了多线程内存映射,似乎当线程数为4时,速度约为350ms/GB,当我添加线程数时,写入速度不再上升.
内存映射代码:
#include <fstream>
#include <chrono>
#include <vector>
#include <cstdint>
#include <numeric>
#include <random>
#include <algorithm>
#include <iostream>
#include <cassert>
#include <thread>
#include <windows.h>
#include <sstream>
// Generate random data
std::vector<int> GenerateData(std::size_t bytes) {
assert(bytes % sizeof(int) == 0);
std::vector<int> data(bytes / sizeof(int));
std::iota(data.begin(), data.end(), 0);
std::shuffle(data.begin(), data.end(), std::mt19937{ std::random_device{}() });
return data;
}
// Memory mapping
int map_write(int* data, int size, int id){
char* name = (char*)malloc(100); …Run Code Online (Sandbox Code Playgroud)