【问题标题】:Why is basic_fstream<unsigned char> order of magnitude slower than basic_fstream<char> on Windows?为什么 basic_fstream<unsigned char> 在 Windows 上比 basic_fstream<char> 慢一个数量级?
【发布时间】:2023-03-18 08:48:01
【问题描述】:

在一个程序中,我正在处理一些使用字节别名的程序,方法如下:

#include <fstream>
#include <vector>
using Byte = unsigned char;

void write(const Byte* buffer, size_t size) {
    std::basic_fstream<Byte> file("1gb_file", std::ios::in | std::ios::out);
    file.write(buffer, size);
    file.flush(); // To ensure the data is being written, to eliminate caching claims
}

int main(){
    auto GB = 1024u * 1024u * 1024u;
    std::vector<Byte> zeros(GB, 0);
    write(zeros.data(), zeros.size());
    return 0;
}

此函数在Byte == unsigned char 上执行的时间:52.0245s 在我全新的 SSD 上,MSVC-x64 处于发布模式。

另一方面,如果我们将定义更改为Byte == char:1.46725s。就是这样。

为什么会有这种差异?在使用标准库方面是否有任何一般的良好做法来避免此类陷阱?

注意(因错误而编辑):正如@SergeyA 指出的那样,在 Linux 上,当给定 unsigned char(在 gcc 和 clang 上)时,代码实际上无法运行。 Windows 上的 GCC 版本也无法运行,这与我之前写的相反。

【问题讨论】:

  • 如果您将 Linux 安装为操作系统,我实际上想知道是否也会发生这种情况,因为我只在 VM 上测试过,无法复制错误,尽管这并没有意义重大(因为在 VM 上“写入磁盘”可能会将所有内容写入 RAM 并稍后刷新)。
  • 在我的 Linux 安装上它根本不起作用。 write 失败,unsigned char 流在 thje 流上设置坏位。据我所知,内部实现细节成员(从名称来看,与转换语言环境有关)是 nullptr。看起来 unsigned char 流并不是真正的主流。
  • 添加检查 file.good() 然后 perror 给出 Invalid or incomplete multibyte or wide character 并且没有写入文件。检查您的退货代码。
  • @stark 你是对的,但这只发生在 Linux 上,我已经相应地修复了帖子。 Windows 版本虽然工作得很好。我实际上没有设法得到那个错误,我得到了和 SergeyA 一样的错误。
  • 其实是Cygwin下的Windows,不是Linux。

标签: c++ windows performance file io


【解决方案1】:

我将在这里硬着头皮猜测它与语言环境有关。根据我掌握的非常有限的信息,它看起来像在 MSVC 无符号字符流中执行语言环境转换,而普通字符流不执行,而只是执行批量 IO。 (请参阅http://en.cppreference.com/w/cpp/io/basic_ostream/write 的注释)。

有趣的是,相同的代码 sn-p 在我使用 g++ 5.4(相当老,我知道)的 Linux 安装上根​​本不起作用。由于流类中的某些内部成员为 nullptr(感兴趣的人是 _M_codecvt)并且流的 badbit 已设置,写入失败。

【讨论】:

  • 我在运行在 linux 上的 VM(ubuntu 16.04,clang 和 gcc)上编译并运行,它的运行速度大致相同。第一次遇到这个bug时我也想过转换,但我不知道是不是这样,将unsigned char的指针转换为char非常便宜,单独转换每个值听起来像是一个非常愚蠢的实现。
  • @Michael,我想,你误解了转换。不是指针的转换,是字符的转换!转换语言环境允许将一个(序列)字符转换为另一个字符。我有 80% 的把握这就是这里发生的事情。顺便说一句,我现在怀疑您认为您需要使用std::fstream&lt;unsigned char&gt; 来存储unsigned char 的数据块。完全不是的情况。
  • 使用 linux g++ 7.2.0 使用Byte=unsigned char 写入对我来说也失败了
  • @SergeyA 我写道“单独转换每个值听起来像是一个非常愚蠢的实现”,我确实考虑过这一点。您显然不需要std::basic_fstream&lt;unsigned char&gt; 来存储它,您只需转换指针,这是正确的做法。其实我的Linux版本有一个错误导致代码同时运行,你其实是对的,代码对gcc下的unsigned char无效,很奇怪。
  • @MFisherKDX 我更新了一些我弄错的东西,我没有检查失败位并且实际上弄错了。现在它在 Linux 上的表现很奇怪,我们只有更多的东西要解释了。
猜你喜欢
  • 1970-01-01
  • 2021-09-08
  • 2014-12-20
  • 1970-01-01
  • 2011-04-06
  • 2012-09-27
  • 1970-01-01
  • 2013-01-19
  • 2014-05-03
相关资源
最近更新 更多