我有一个超快的M.2驱动器。有多快?这不重要,因为我无论如何都不能利用这个速度。所以我才问这个问题。
我有一个应用程序需要很多内存。所以它不能放进内存里。幸运的是,它并不是一下子就需要的。相反,它用于保存计算的中间结果。
不幸的是,应用程序无法足够快地写入和读取这些数据。我尝试使用多个读取器和写入线程,但这只会使情况变得更糟(后来我读到这是因为this)。
因此,我的问题是:在C++中是否可能有真正的异步文件IO来充分利用所宣传的每秒千兆字节?如果它是如何(在跨平台的方式)?
如果你知道这样的任务,你也可以推荐一个很好的库,因为我认为重新发明轮子是没有意义的。
编辑:
下面的代码展示了如何在我的程序中实现文件IO。它不是从上述程序,因为它不会是最小的。然而,这一次却削弱了这一问题。别介意Windows.h。它仅用于设置线程关联。在实际的程序中,我也设置了亲和力,这就是我包含它的原因。
#include <fstream>
#include <thread>
#include <memory>
#include <string>
#include <Windows.h> // for SetThreadAffinityMask()
void stress_write(unsigned bytes, int num)
{
std::ofstream out("temp" + std::to_string(num));
for (unsigned i = 0; i < bytes; ++i)
{
out << char(i);
}
}
void lock_thread(unsigned core_idx)
{
SetThreadAffinityMask(GetCurrentThread(), 1LL << core_idx);
}
int main()
{
std::ios_base::sync_with_stdio(false);
lock_thread(0);
auto worker_count = std::thread::hardware_concurrency() - 1;
std::unique_ptr<std::thread[]> threads = std::make_unique<std::thread[]>(worker_count); // faster than std::vector
for (int i = 0; i < worker_count; ++i)
{
threads[i] = std::thread(
[](unsigned idx) {
lock_thread(idx);
stress_write(1'000'000'000, idx);
},
i + 1
);
}
stress_write(1'000'000'000, 0);
for (int i = 0; i < worker_count; ++i)
{
threads[i].join();
}
}正如您所看到的,它只是普通的旧fstream。在我的机器上,它使用100%的CPU,但只有7-9%的磁盘(大约190 my /s)。我想知道是否可以增加。
发布于 2020-01-10 19:28:02
要达到10倍的速度,最简单的方法就是改变这种情况:
void stress_write(unsigned bytes, int num)
{
std::ofstream out("temp" + std::to_string(num));
for (unsigned i = 0; i < bytes; ++i)
{
out << char(i);
}
}对此:
void stress_write(unsigned bytes, int num)
{
constexpr auto chunk_size = (1u << 12u); // tune as needed
std::ofstream out("temp" + std::to_string(num));
for (unsigned chunk = 0; chunk < (bytes+chunk_size-1)/chunk_size; ++chunk)
{
char chunk_buff[chunk_size];
auto count = (std::min)( bytes - chunk_size*chunk, chunk_size );
for (unsigned j = 0; j < count; ++j)
{
unsigned i = j + chunk_size*chunk;
chunk_buff[j] = char(i); // processing
}
out.write( chunk_buff, count );
}
}在发送到流的std之前,我们分组写入多达4096字节。
流操作有许多烦人的、很难让编译器删除的虚拟调用,当您一次只编写几个字节时,这些调用控制了性能。
通过将数据分块成更大的部分,我们使得vtable查找变得非常罕见,以至于它们不再占主导地位。
有关原因的更多细节,请参见this SO post。
要获得最后一点性能,您可能必须使用类似boost.asio之类的工具,或者访问平台原始异步文件io库。
但是,当你工作在< 10%的驱动器带宽,而栏杆你的CPU,瞄准低挂水果第一。
https://stackoverflow.com/questions/59667777
复制相似问题