C++ 变暖 std 向量

2023-11-30

为什么第二次填充 std::vector 更快?即使从一开始就预留了空间?

int total = 1000000;

struct BaseClass {
  float m[16];
  int id;

  BaseClass(int _id) { id = _id; }
};

int main() {

  std::vector<BaseClass> ar;
  ar.reserve(total);

  {
    auto t_start = std::chrono::high_resolution_clock::now();
    for (int var = 0; var < total; ++var) {
      ar.emplace_back(var);
    }
    auto t_end = std::chrono::high_resolution_clock::now();
    std::cout << std::chrono::duration_cast<std::chrono::milliseconds>(
                     t_end - t_start).count() << "\n";
    ar.clear();
  }

  {
    auto t_start = std::chrono::high_resolution_clock::now();
    for (int var = 0; var < total; ++var) {
      ar.emplace_back(var);
    }
    auto t_end = std::chrono::high_resolution_clock::now();
    std::cout << std::chrono::duration_cast<std::chrono::milliseconds>(
                     t_end - t_start).count() << "\n";
    ar.clear();
  }

  {
    auto t_start = std::chrono::high_resolution_clock::now();
    for (int var = 0; var < total; ++var) {
      ar.emplace_back(var);
    }
    auto t_end = std::chrono::high_resolution_clock::now();
    std::cout << std::chrono::duration_cast<std::chrono::milliseconds>(
                     t_end - t_start).count() << "\n";
    ar.clear();
  }

  return 0;
}

在线预览:http://coliru.stacked-crooked.com/a/229e4ba47adddb1a

RESULTS:
118
23
21

附:我问如果向量减慢的唯一原因是分配/重新分配,为什么它会变得更快。我们在开始之前分配了数组。


第一次运行比其他两次慢的原因是运行时尚未从操作系统获取内存页面。

我对您的程序进行了检测,以输出任务在开始时以及在上述三个阶段中的每个阶段之后发生的主要和次要页面错误的数量。 (注意:这适用于 Linux。不知道它是否适用于您使用的任何操作系统。)代码:

Note: updated to latest, with reserve() moved to the top and wrapped in its own getrusage call.

#include <ctime>
#include <chrono>
#include <iostream>
#include <vector>

#include <sys/time.h>
#include <sys/resource.h>

using namespace std;

int total = 1000000;

struct BaseClass {
  float m[16];
  int id;

  BaseClass(int _id) { id = _id; }
};

int main() {

  std::vector<BaseClass> ar;
  struct rusage r;
  {
    auto t_start = std::chrono::high_resolution_clock::now();
     }

  getrusage(RUSAGE_SELF, &r);
  cout << "minflt: " << r.ru_minflt << " majflt: " << r.ru_majflt << endl;

  ar.reserve(total);

  getrusage(RUSAGE_SELF, &r);
  cout << "minflt: " << r.ru_minflt << " majflt: " << r.ru_majflt << endl;

  {
    auto t_start = std::chrono::high_resolution_clock::now();
    for (int var = 0; var < total; ++var) {
      ar.emplace_back(var);
    }
    auto t_end = std::chrono::high_resolution_clock::now();
    std::cout << std::chrono::duration_cast<std::chrono::milliseconds>(
                     t_end - t_start).count() << "\n";
    ar.clear();
  }

  getrusage(RUSAGE_SELF, &r);
  cout << "minflt: " << r.ru_minflt << " majflt: " << r.ru_majflt << endl;

  {
    auto t_start = std::chrono::high_resolution_clock::now();
    for (int var = 0; var < total; ++var) {
      ar.emplace_back(var);
    }
    auto t_end = std::chrono::high_resolution_clock::now();
    std::cout << std::chrono::duration_cast<std::chrono::milliseconds>(
                     t_end - t_start).count() << "\n";
    ar.clear();
  }

  getrusage(RUSAGE_SELF, &r);
  cout << "minflt: " << r.ru_minflt << " majflt: " << r.ru_majflt << endl;

  {
    auto t_start = std::chrono::high_resolution_clock::now();
    for (int var = 0; var < total; ++var) {
      ar.emplace_back(var);
    }
    auto t_end = std::chrono::high_resolution_clock::now();
    std::cout << std::chrono::duration_cast<std::chrono::milliseconds>(
                     t_end - t_start).count() << "\n";
    ar.clear();
  }

  getrusage(RUSAGE_SELF, &r);
  cout << "minflt: " << r.ru_minflt << " majflt: " << r.ru_majflt << endl;

  return 0;
}

然后我在我的盒子上运行它。结果很有启发:

minflt: 343 majflt: 0
minflt: 367 majflt: 0
48    minflt: 16968 majflt: 0
16
minflt: 16968 majflt: 0
15
minflt: 16968 majflt: 0

请注意,第一个测量的 for 循环发生了超过 16,000 个小错误。这些错误导致内存可供应用程序使用,并导致运行时间变慢。此后不再发生其他故障。相比之下,reserve()调用本身只发生了24个小错误。

在大多数现代虚拟内存操作系统中,操作系统实现了惰性内存分配,即使其上运行的软件没有实现。当运行时从操作系统请求额外内存时,操作系统会记录该请求。如果请求成功,运行时现在就有可用的新虚拟地址范围。 (细节因调用的 API 和操作系统而异,但本质是相同的。)操作系统可能将虚拟地址范围指向标记为只读的单个零填充页。

操作系统确实not必须使这些页面立即可供任务使用。相反,操作系统会等待,直到任务实际尝试写入为其分配的内存。此时,操作系统会分配一个物理页来支持分配给该任务的虚拟页。这在 UNIX 术语中被称为“小错误”。这个过程可能会很昂贵。

您的任务正在测量的正是这种惰性分配。

为了证明这一点,我做了一个strace以及应用程序的。有意义的部分如下。

getrusage(RUSAGE_SELF, {ru_utime={0, 0}, ru_stime={0, 0}, ...}) = 0
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fe3aa339000
write(1, "minflt: 328 majflt: 0\n", 22) = 22
mmap(NULL, 68001792, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fe3a551c000
getrusage(RUSAGE_SELF, {ru_utime={0, 0}, ru_stime={0, 0}, ...}) = 0
write(1, "minflt: 352 majflt: 0\n", 22) = 22
write(1, "52\n", 3)                     = 3
getrusage(RUSAGE_SELF, {ru_utime={0, 30000}, ru_stime={0, 20000}, ...}) = 0
write(1, "minflt: 16953 majflt: 0\n", 24) = 24
write(1, "20\n", 3)                     = 3
getrusage(RUSAGE_SELF, {ru_utime={0, 50000}, ru_stime={0, 20000}, ...}) = 0
write(1, "minflt: 16953 majflt: 0\n", 24) = 24
write(1, "15\n", 3)                     = 3
getrusage(RUSAGE_SELF, {ru_utime={0, 70000}, ru_stime={0, 20000}, ...}) = 0
write(1, "minflt: 16953 majflt: 0\n", 24) = 24
munmap(0x7fe3a551c000, 68001792)        = 0
exit_group(0)                           = ?

正如你所看到的,任务分配的内存是mmap前两个之间的调用getrusage系统调用。然而,这一步只造成了24个小错误。所以,尽管 C++ 是not由于懒惰,Linux 懒于为任务分配内存。

具体来说,第一个mmap调用似乎为第一个分配了一个 I/O 缓冲区write信息。第二mmap发生调用(分配 68001792 字节)before第二getrusage称呼。然而,您可以看到在这次运行中两者之间仅发生了 24 个额外故障。

眼尖的人会注意到这次运行的数字与我上面显示的数字略有不同。我已经多次运行这个可执行文件,每次数字都会略有变化。但是,他们总是处于同一个大致范围内。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++ 变暖 std 向量 的相关文章

随机推荐

  • 如何获取生成的 java 进程的 PID

    我正在编写几个 java 程序 在完成我想做的任何事情后 需要在单独的 JVM 中杀死 清理 为此 我需要获取我正在创建的 java 进程的 PID jps l可在 Windows 和 Unix 上运行 您可以使用 java 程序调用此命令
  • 带 url 重定向的 Rails 句柄 404

    我希望使用 Rails 将链接重定向到互联网上 我确信这些链接从我的旧域到新域 我想使用地址 example com about about 将不再存在 在我的 application controller 中获取 404 检查 url 然
  • NSDate 因连续操作而崩溃

    我下面有以下代码 旨在将名为 today 的类变量向前或向后更改一天 它会工作一次 但之后就会崩溃 无论我按左键还是右键 它都会做同样的事情 我究竟做错了什么 今天的 var 是一个类 var 发起为 today NSDate date 这
  • VBA Powerpoint - 如何突出显示选定的文本

    我想将所选文本突出显示为某种颜色 但这不起作用 你能帮我吗 Sub ShadingLtYellow ActiveWindow Selection TextRange HighlightColor RGB RGB 255 255 175 En
  • 为什么 Pinia/Vuex 比具有服务类的经典方法更受青睐? [关闭]

    Closed 这个问题是基于意见的 目前不接受答案 皮尼亚 Vuex Pinia Vuex 以及 Redux 被设计为 单一事实来源 您可以拥有一个或多个存储来保存应用程序数据 并且可以从任何地方获取这些数据 Pinia 商店如下所示 ex
  • 如何在nuxt中添加流(flowtype)支持?

    我想为 nuxt 项目添加流支持 我的项目使用 webpack 和 babel 我可以在某处找到工作示例吗 如果我跑flow check 没有错误 当我运行时yarn run dev 我收到语法错误 我知道有这些未答复的 问题在那里 我再次
  • 编码返回“未知”

    对于这个例子 http pastebin com QyebfD1pz3 和 cvc4 返回 未知 作为 check sat 的结果 两者对于原因都不是很详细 有没有办法让 z3 关于其执行更加详细 你的脚本使用了这个策略 s Then si
  • IE6 中的 event.currentTarget

    我有一个事件处理程序 我将其附加到一个元素以捕获冒泡的单击事件 我需要一个reliable获取元素的方法caught事件 而不是触发它的元素 该特定元素高于 srcElement target 的级别数量是任意的 因此使用 ParentNo
  • 使用 WebServiceTemplate 设置自定义标头

    我在 Spring Boot 中使用 WebServiceTemplate 并使用 marshalSendAndReceive 调用目标服务 如何在请求中设置自定义 HTTP 标头 您需要使用 WebServiceMessageCallba
  • 在 dropwizard 中运行异步作业并轮询其状态

    在 dropwizard 中 我需要实现异步作业并轮询它们的状态 我在资源中有两个端点 Path jobs Component public class MyController POST Produces MediaType APPLIC
  • 在 mac 中安装 PHP INTL 不正确

    我已经安装了php56 intl using Homebrew像这样 brew install php56 intl当我这样做时php m grep intl它给了我intl 但是当我检查我的phpinfo 文件 不显示intl 不知道我错
  • 导致 JavaFX 2.0 中 TableView 不响应鼠标单击

    我想要一个 JavaFX 2 0 TableView 但我不希望它响应鼠标单击 当然 我可以禁用控件 小部件 但它会显示为禁用 tableview setSelectionModel null 给出了我想要的行为 但 UI 转储了抱怨 nu
  • 在 Flex 中的组件之间共享数据的最佳方式是什么?

    我正在为新工作开发一个 Flex 应用程序 这有点像一个训练轮应用程序 我正在学习这门语言 这不是一个需要与服务对话才能完成工作的应用程序 整个应用程序中有一些组合框实例共享相同的一组可能值 例如 选择状态 进行中 拒绝 完成 我希望它们使
  • 使用 Indy 发布并且文件名包含希腊字符时文件上传失败

    我正在尝试实施一个POST到网络服务 我需要发送一个类型为可变的文件 docx pdf txt 以及 JSON 格式的字符串 我已成功使用类似于以下的代码成功发布文件 procedure DoRequest var Http TIdHTTP
  • 使用 python xml.sax 解析 XML 实体

    使用 xml sax 使用 python 解析 XML 但我的代码无法捕获实体 为什么skippedEntity 或resolveEntity 不报告以下内容 import os import cStringIO import xml sa
  • 如何让mysql接受外部连接

    我有一个 VPS 我想让 mysql DB 接受外部连接 例如从我的电脑 我在服务器上安装了 Debian Linux 我上网查了一些教程 他们说要注释掉 bind address 127 0 0 1 但这似乎没有帮助 VPS 有什么特别的
  • 系统上未安装语音或当前安全设置中没有可用的语音

    尝试使用 SpeechSynthesizer 在 C 上创建 wav 文件时 IIS 服务器出现异常 当应用程序无法访问语音供 SpeechSynthesizer 使用时 会导致此错误 第一个可能的原因是系统上缺少任何已安装的语音 很可能这
  • yii 中 utf8 字符和 htmlspecialchars 错误

    我在 yii 中的字符编码有问题 如果我创建一个新的网络应用程序 Yii framework framework yiic webapp MyTest 然后转到 protected views layouts main php 并将页脚更改
  • Linux下C语言清除串口数据?

    我正在测试发送和接收程序 代码如下 main 函数如下 include lib h int fd int initport int fd struct termios options Get the current options for
  • C++ 变暖 std 向量

    为什么第二次填充 std vector 更快 即使从一开始就预留了空间 int total 1000000 struct BaseClass float m 16 int id BaseClass int id id id int main