首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >C++中真正的异步文件IO

C++中真正的异步文件IO
EN

Stack Overflow用户
提问于 2020-01-09 15:56:24
回答 1查看 6.1K关注 0票数 9

我有一个超快的M.2驱动器。有多快?这不重要,因为我无论如何都不能利用这个速度。所以我才问这个问题。

我有一个应用程序需要很多内存。所以它不能放进内存里。幸运的是,它并不是一下子就需要的。相反,它用于保存计算的中间结果。

不幸的是,应用程序无法足够快地写入和读取这些数据。我尝试使用多个读取器和写入线程,但这只会使情况变得更糟(后来我读到这是因为this)。

因此,我的问题是:在C++中是否可能有真正的异步文件IO来充分利用所宣传的每秒千兆字节?如果它是如何(在跨平台的方式)?

如果你知道这样的任务,你也可以推荐一个很好的库,因为我认为重新发明轮子是没有意义的。

编辑:

下面的代码展示了如何在我的程序中实现文件IO。它不是从上述程序,因为它不会是最小的。然而,这一次却削弱了这一问题。别介意Windows.h。它仅用于设置线程关联。在实际的程序中,我也设置了亲和力,这就是我包含它的原因。

代码语言:javascript
复制
#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)。我想知道是否可以增加。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-01-10 19:28:02

要达到10倍的速度,最简单的方法就是改变这种情况:

代码语言:javascript
复制
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);
  }
}

对此:

代码语言:javascript
复制
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,瞄准低挂水果第一。

票数 11
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/59667777

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档