- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
以下代码片段采用一个命令行参数,该参数表示要生成的线程数以同时运行一个简单的 for 循环。
如果传递的参数为 0,则不会生成 std::thread
。
在 gcc 4.9.2 上,./snippet 0
比 ./snippet 1
平均花费 10%,即生成一个 std 的版本: :thread
执行循环比仅在 main
中执行循环的版本更快。
有人知道这是怎么回事吗? clang-4 根本没有表现出这种行为(带有一个 std::thread
的版本较慢),gcc 6.2 具有带有一个 std::thread
的版本运行得稍微慢一点更快(以十次试验中花费的最少时间作为测量值)。
这是片段:ScopedNanoTimer
只是一个简单的 RAII 计时器。我正在使用 -g -O3 -pthread -std=c++11
进行编译。
#include <thread>
#include <vector>
int main(int argc, char** argv) {
// setup
if (argc < 2)
return 1;
const unsigned n_threads = std::atoi(argv[1]);
const auto n_iterations = 1000000000ul / (n_threads > 0u ? n_threads : n_threads + 1);
// define workload
auto task = [n_iterations]() {
volatile auto sum = 0ul;
for (auto i = 0ul; i < n_iterations; ++i) ++sum;
};
// time and print
if (n_threads == 0) {
task();
} else {
std::vector<std::thread> threads;
for (auto i = 0u; i < n_threads; ++i) threads.emplace_back(task);
for (auto &thread : threads) thread.join();
}
return 0;
}
编辑
按照评论中的建议,我试图让编译器混淆这样一个事实,即对于 n_threads == 0
的逻辑分支,迭代次数是先验已知的。我将相关行更改为
const auto n_iterations = 1000000000ul / (n_threads > 0u ? n_threads : n_threads + 1);
我还删除了执行 10 次的外部 for 循环和所有提及的 ScopedNanoTimer。这些更改现在反射(reflect)在上面的代码片段中。
我使用上面指示的标志编译并在装有 Debian Linux、内核版本 3.16.39-1+deb8u2 和处理器 Intel(R) Core(TM) i7-4790 CPU @ 3.60GHz、quad 的工作站上执行了几次-核。关闭所有其他程序,关闭 cpu 节流/intel speed-step/turbo-boost 并将 cpu 调控器策略设置为“性能”。互联网连接已关闭。
趋势始终是,使用 gcc-4.9.2 编译没有 std::thread
的版本比生成一个线程的版本快大约 10%。相反,clang-4 具有相反的(预期的)行为。
以下测量结果使我确信问题出在 gcc-4.9.2 次优优化中,与上下文切换或测量质量差无关。话虽如此,即使是 Godbolt 的编译器资源管理器也没有清楚地向我展示 gcc 在做什么,所以我认为这个问题没有得到回答。
使用 g++-4.9.2 进行时间+上下文切换测量
~$ g++ -std=c++11 -pthread -g -O3 snippet.cpp -o snippet_gcc
~$ for i in $(seq 1 10); do /usr/bin/time -v 2>&1 ./snippet_gcc 0 | egrep '((wall clock)|(switch))'; done
Elapsed (wall clock) time (h:mm:ss or m:ss): 0:02.08
Voluntary context switches: 1
Involuntary context switches: 6
Elapsed (wall clock) time (h:mm:ss or m:ss): 0:02.08
Voluntary context switches: 1
Involuntary context switches: 5
Elapsed (wall clock) time (h:mm:ss or m:ss): 0:02.08
Voluntary context switches: 1
Involuntary context switches: 7
Elapsed (wall clock) time (h:mm:ss or m:ss): 0:02.08
Voluntary context switches: 1
Involuntary context switches: 6
Elapsed (wall clock) time (h:mm:ss or m:ss): 0:01.90
Voluntary context switches: 1
Involuntary context switches: 3
Elapsed (wall clock) time (h:mm:ss or m:ss): 0:02.08
Voluntary context switches: 1
Involuntary context switches: 6
Elapsed (wall clock) time (h:mm:ss or m:ss): 0:02.08
Voluntary context switches: 1
Involuntary context switches: 5
Elapsed (wall clock) time (h:mm:ss or m:ss): 0:02.08
Voluntary context switches: 1
Involuntary context switches: 6
Elapsed (wall clock) time (h:mm:ss or m:ss): 0:02.08
Voluntary context switches: 1
Involuntary context switches: 2
Elapsed (wall clock) time (h:mm:ss or m:ss): 0:02.08
Voluntary context switches: 1
Involuntary context switches: 4
~$ for i in $(seq 1 10); do /usr/bin/time -v 2>&1 ./snippet_gcc 1 | egrep '((wall clock)|(switch))'; done
Elapsed (wall clock) time (h:mm:ss or m:ss): 0:01.79
Voluntary context switches: 2
Involuntary context switches: 4
Elapsed (wall clock) time (h:mm:ss or m:ss): 0:01.95
Voluntary context switches: 2
Involuntary context switches: 4
Elapsed (wall clock) time (h:mm:ss or m:ss): 0:01.81
Voluntary context switches: 2
Involuntary context switches: 4
Elapsed (wall clock) time (h:mm:ss or m:ss): 0:01.87
Voluntary context switches: 2
Involuntary context switches: 5
Elapsed (wall clock) time (h:mm:ss or m:ss): 0:01.87
Voluntary context switches: 2
Involuntary context switches: 4
Elapsed (wall clock) time (h:mm:ss or m:ss): 0:01.97
Voluntary context switches: 2
Involuntary context switches: 3
Elapsed (wall clock) time (h:mm:ss or m:ss): 0:01.87
Voluntary context switches: 2
Involuntary context switches: 4
Elapsed (wall clock) time (h:mm:ss or m:ss): 0:01.85
Voluntary context switches: 2
Involuntary context switches: 4
Elapsed (wall clock) time (h:mm:ss or m:ss): 0:01.87
Voluntary context switches: 2
Involuntary context switches: 6
Elapsed (wall clock) time (h:mm:ss or m:ss): 0:01.95
Voluntary context switches: 2
Involuntary context switches: 5
使用 clang++-4.0 进行时间+上下文切换测量
~$ clang++ -std=c++11 -pthread -g -O3 snippet.cpp -o snippet_clang
~$ for i in $(seq 1 10); do /usr/bin/time -v 2>&1 ./snippet_clang 0 | egrep '((wall clock)|(switch))'; done
Elapsed (wall clock) time (h:mm:ss or m:ss): 0:01.67
Voluntary context switches: 1
Involuntary context switches: 6
Elapsed (wall clock) time (h:mm:ss or m:ss): 0:01.67
Voluntary context switches: 1
Involuntary context switches: 4
Elapsed (wall clock) time (h:mm:ss or m:ss): 0:01.67
Voluntary context switches: 1
Involuntary context switches: 5
Elapsed (wall clock) time (h:mm:ss or m:ss): 0:01.67
Voluntary context switches: 1
Involuntary context switches: 4
Elapsed (wall clock) time (h:mm:ss or m:ss): 0:01.67
Voluntary context switches: 1
Involuntary context switches: 7
Elapsed (wall clock) time (h:mm:ss or m:ss): 0:01.67
Voluntary context switches: 1
Involuntary context switches: 3
Elapsed (wall clock) time (h:mm:ss or m:ss): 0:01.67
Voluntary context switches: 1
Involuntary context switches: 4
Elapsed (wall clock) time (h:mm:ss or m:ss): 0:01.67
Voluntary context switches: 1
Involuntary context switches: 4
Elapsed (wall clock) time (h:mm:ss or m:ss): 0:01.67
Voluntary context switches: 1
Involuntary context switches: 3
Elapsed (wall clock) time (h:mm:ss or m:ss): 0:01.67
Voluntary context switches: 1
Involuntary context switches: 4
~$ for i in $(seq 1 10); do /usr/bin/time -v 2>&1 ./snippet_clang 1 | egrep '((wall clock)|(switch))'; done
Elapsed (wall clock) time (h:mm:ss or m:ss): 0:01.67
Voluntary context switches: 2
Involuntary context switches: 6
Elapsed (wall clock) time (h:mm:ss or m:ss): 0:01.67
Voluntary context switches: 2
Involuntary context switches: 6
Elapsed (wall clock) time (h:mm:ss or m:ss): 0:01.67
Voluntary context switches: 2
Involuntary context switches: 5
Elapsed (wall clock) time (h:mm:ss or m:ss): 0:01.67
Voluntary context switches: 2
Involuntary context switches: 4
Elapsed (wall clock) time (h:mm:ss or m:ss): 0:01.67
Voluntary context switches: 2
Involuntary context switches: 4
Elapsed (wall clock) time (h:mm:ss or m:ss): 0:01.67
Voluntary context switches: 2
Involuntary context switches: 5
Elapsed (wall clock) time (h:mm:ss or m:ss): 0:01.67
Voluntary context switches: 2
Involuntary context switches: 2
Elapsed (wall clock) time (h:mm:ss or m:ss): 0:01.67
Voluntary context switches: 2
Involuntary context switches: 3
Elapsed (wall clock) time (h:mm:ss or m:ss): 0:01.67
Voluntary context switches: 2
Involuntary context switches: 4
Elapsed (wall clock) time (h:mm:ss or m:ss): 0:01.67
Voluntary context switches: 2
Involuntary context switches: 7
最佳答案
我认为您可能是不良测试样本的受害者。我试图重现此行为,并且在为每个选项运行每个选项 10 次左右之后,我发现我收到的时间具有相对较高的差异。我使用/usr/bin/time -v 运行了更多测试,发现程序的执行时间与程序经历的非自愿上下文切换的次数密切相关。
Option 0: No threads
time, context switches
20.32, 1806
20.09, 2139
21.01, 1916
21.13, 1873
21.15, 1847
18.67, 1617
19.06, 1692
17.94, 1546
21.40, 1867
18.64, 1629
Option 1: Threads
time, context switches
19.68, 1750
19.60, 1740
19.35, 1783
19.60, 1726
19.95, 1823
20.42, 1800
19.54, 1745
19.40, 1699
19.36, 1703
我认为您可能只是在操作系统的可变工作负载期间运行了基准测试。从我上面的时间数据可以看出,超过 20 秒的时间都是在操作系统高负载期间收集的。同样,在低负载期间收集的时间少于 19 秒。
从逻辑上讲,我明白为什么分派(dispatch)线程的循环应该运行得更慢。创建线程的开销相对于循环的操作来说是很高的,它只是简单地增加一个数字。这会导致运行程序所需的用户时间增加。问题是,与整个循环的执行时间相比,这种用户时间的增加可能可以忽略不计。在程序的整个生命周期中,您只会创建 10 个额外的线程,并且在这些线程中执行计算与在主线程中简单地执行这些计算应该没有什么区别。在整个程序过程中,您正在执行数十亿次其他操作,这些操作隐藏了用户时间的增加。如果您真的想对线程的创建时间进行基准测试,您可以编写一个程序来创建大量线程,而不会做太多其他事情。您还应该小心地在后台进程尽可能少的环境中运行此类基准测试。
这可能不是问题的全部,但我认为考虑仍然很重要。
关于c++ - 为什么这个简单的 lambda 在 std::thread 中始终比在 gcc 4.9.2 的 main 函数中运行得更快?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44264397/
我正在努力实现以下目标, 假设我有字符串: ( z ) ( A ( z ) ( A ( z ) ( A ( z ) ( A ( z ) ( A ) ) ) ) ) 我想编写一个正则
给定: 1 2 3 4 5 6
很难说出这里要问什么。这个问题模棱两可、含糊不清、不完整、过于宽泛或夸夸其谈,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开,visit the help center . 关闭 1
大家好,我卡颂。 Svelte问世很久了,一直想写一篇好懂的原理分析文章,拖了这么久终于写了。 本文会围绕一张流程图和两个Demo讲解,正确的食用方式是用电脑打开本文,跟着流程图、Demo一
身份证为15位或者18位,15位的全为数字,18位的前17位为数字,最后一位为数字或者大写字母”X“。 与之匹配的正则表达式: ?
我们先来最简单的,网页的登录窗口; 不过开始之前,大家先下载jquery的插件 本人习惯用了vs2008来做网页了,先添加一个空白页 这是最简单的的做法。。。先在body里面插入 <
1、MySQL自带的压力测试工具 Mysqlslap mysqlslap是mysql自带的基准测试工具,该工具查询数据,语法简单,灵活容易使用.该工具可以模拟多个客户端同时并发的向服务器发出
前言 今天大姚给大家分享一款.NET开源(MIT License)、免费、简单、实用的数据库文档(字典)生成工具,该工具支持CHM、Word、Excel、PDF、Html、XML、Markdown等
Go语言语法类似于C语言,因此熟悉C语言及其派生语言( C++、 C#、Objective-C 等)的人都会迅速熟悉这门语言。 C语言的有些语法会让代码可读性降低甚至发生歧义。Go语言在C语言的
我正在使用快速将 mkv 转换为 mp4 ffmpeg 命令 ffmpeg -i test.mkv -vcodec copy -acodec copy new.mp4 但不适用于任何 mkv 文件,当
我想计算我的工作簿中的工作表数量,然后从总数中减去特定的工作表。我错过了什么?这给了我一个对象错误: wsCount = ThisWorkbook.Sheets.Count - ThisWorkboo
我有一个 perl 文件,用于查看文件夹中是否存在 ini。如果是,它会从中读取,如果不是,它会根据我为它制作的模板创建一个。 我在 ini 部分使用 Config::Simple。 我的问题是,如果
尝试让一个 ViewController 通过标准 Cocoa 通知与另一个 ViewController 进行通信。 编写了一个简单的测试用例。在我最初的 VC 中,我将以下内容添加到 viewDi
我正在绘制高程剖面图,显示沿路径的高程增益/损失,类似于下面的: Sample Elevation Profile with hand-placed labels http://img38.image
嗨,所以我需要做的是最终让 regStart 和 regPage 根据点击事件交替可见性,我不太担心编写 JavaScript 函数,但我根本无法让我的 regPage 首先隐藏。这是我的代码。请简单
我有一个非常简单的程序来测量一个函数花费了多少时间。 #include #include #include struct Foo { void addSample(uint64_t s)
我需要为 JavaScript 制作简单的 C# BitConverter。我做了一个简单的BitConverter class BitConverter{ constructor(){} GetBy
已关闭。这个问题是 not reproducible or was caused by typos 。目前不接受答案。 这个问题是由拼写错误或无法再重现的问题引起的。虽然类似的问题可能是 on-top
我是 Simple.Data 的新手。但我很难找到如何进行“分组依据”。 我想要的是非常基本的。 表格看起来像: +________+ | cards | +________+ | id |
我现在正在开发一个 JS UDF,它看起来遵循编码。 通常情况下,由于循环计数为 2,Alert Msg 会出现两次。我想要的是即使循环计数为 3,Alert Msg 也只会出现一次。任何想法都
我是一名优秀的程序员,十分优秀!