- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我创建了一个非常简单的测试程序来计算一些标量 c 和矩阵 A 的 c*A。您可以在这里在线运行它 here或将以下代码粘贴到您最喜欢的文本编辑器中:
#include <iostream>
#include <time.h>
#include <chrono>
#include <thread>
void fill_rand_matrix(double* mat, int n){
for (int i=0;i<n;i++){
mat[i]=static_cast <double> (rand()) / static_cast <double> (RAND_MAX)*20-10;
}
}
void test(size_t m, size_t n, double alpha, double* X) {
for (int j = 0; j < m; ++j) {
for (int i = 0; i < n; ++i) {
X[i+ j*n] *= alpha;
}
}
}
int main()
{
int m=10000;
int n=10000;
double res_scaling=0.5;
double* res=new double[m*n];
fill_rand_matrix(res,n*m);
auto begin1 = std::chrono::steady_clock::now();
std::thread t1(test,0.5*m,n,res_scaling,res);
std::thread t2(test,0.5*m,n,res_scaling,(double*)(res+(m/2)*n));
t1.join();
t2.join();
auto end1= std::chrono::steady_clock::now();
std::cout << "Time taken multithreaded = " << std::chrono::duration_cast<std::chrono::milliseconds>(end1 - begin1).count() << "[ms]" << std::endl;
auto begin2 = std::chrono::steady_clock::now();
test(m,n,res_scaling,res);
auto end2= std::chrono::steady_clock::now();
std::cout << "Time taken singlethreaded = " << std::chrono::duration_cast<std::chrono::milliseconds>(end2 - begin2).count() << "[ms]" << std::endl;
return 0;
}
当我多次运行这段代码时,多线程版本要么比单线程变体快一点点,要么比单线程变体慢一点。如果我添加超过 2 个线程,甚至会发生这种情况。多线程似乎没有任何好处,尽管问题应该几乎可以随内核数量完美扩展。此外,我设置的矩阵大小越高,运行时间的波动就越大,有时波动高达 20 倍。
你知道这里发生了什么吗?
最佳答案
我的知识不足以给出明确的答案,但由于目前还没有答案,我会尽力而为:
对大小为 L 的数组进行多次连续 迭代(其中 L 大于您的数组的大小最大缓存)将无法利用任何缓存来对数组进行新的缓存行访问(因为缓存使用 LRU 的变体)。使用快速 计算快速迭代大小为 L 的数组意味着访问(主)内存是瓶颈,并且会占用 共享内存总线 用于所有正在运行的进程/线程。添加更多同样受主内存访问限制的线程只会导致它们之间的竞争。
(如果非常聪明,您的缓存可能会在每个新数组数据进入 L2 缓存之前丢弃它,意识到在它被推出之前您无法使用它。这不会影响这个过程,但会为其他人留下更多的缓存空间。)
对我来说,使用 g++ -std=c++17 -O3 -pthread -S -fverbose-asm
...用 movups
给出汇编输出与该行相关联的指令两次:
X[i+ j*n] *= alpha; // line 17
movups
是 x86 parallelisation (SIMD) instruction .像这样的 SIMD 指令通常把 4 double
s 到一个巨大的寄存器上以非常快速地进行计算( ~10 clock cycles all up ,但如果我错了请纠正我)。将其乘以 4 得到在缓存行上完成的工作:~40 个周期。如果您不使用 x86,那么您可能正在使用具有类似并行化指令的 CPU。
主内存访问速度很慢(大约需要 100-200 个时钟周期才能从主内存中获取缓存行 [缓存行 = 64 字节的 block ~= 16 double ])。
但是,您的 CPU 会尝试通过预取数据来帮助您,因为您总是以比数据总线更快的速率从主内存请求数据如果幸运的话,预取可能只会帮助您将等待时间从大约 100 分钟减少到 60 分钟。无论哪种方式,等待主内存访问仍然是瓶颈。
请注意,这也适用于另一个方向,您可以用更新的数组值填充缓存,但在 8MB 左右之后,您将需要不断地将数据发送回主内存。所以我们的上述估计确实是乐观的。
test
函数有一个小错误:
j < m
和 i < n
是有符号/无符号的比较。
关于c++ - 多线程程序比单线程程序慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64607939/
此代码似乎在启用优化的广泛使用的编译器上中断,尽管它在 Visual Studio 中运行良好。 struct foo { foo(int a) { s[0] = '0'+a%10;s[1]
我想要一个图表,其中有一个单线箭头,如下所示: 1 2 3 4 5 或者像这样(其中/假设是一个箭头:)): \/ -----------------
我正在为 Java 编写自定义规则。有两个 Tree.KIND 实例(STRING_LITERAL 和 ASSIGNMENT)需要捕获。有一个特定的行,字符串文字和赋值的逻辑都会引发问题。但 Sona
Rosettacode.org 在 Ruby 中有这个出色的单行 FizzBuzz 解决方案。 1.upto(100){|n|puts'FizzBuzz '[i=n**4%-15,i+13]||n
很多时候我使用了这个命令,它在当前目录打开了一个临时的 HTTP 服务器: python3 -m http.server 现在我需要接收文件,有没有打开ftp服务器的一行命令? 我只是在寻找一个命令行
相关主题 std::unique_ptr, deleters and the Win32 API 要将 Win32 句柄用作 RAII,我可以使用以下行 std::unique_ptr::type,
我认为必须有一个单行 Guava 解决方案来将一个不可变列表转换为另一个不可变列表,但我找不到它。假设我们有以下对象: ImmutableList input = ImmutableList.of("
我有以下 Highcharts ( http://www.highcharts.com ) 散点图。请注意,轴从 -10 开始,到 10 停止,中间为 0。我希望每条 0 线的宽度或颜色都与其他线不同
我有一个项目需要将一个视频文件与另一个音频文件合并。预期的输出是一个视频文件,其中包含来自实际视频的音频和合并后的音频文件。输出视频文件的长度将与实际视频文件的大小相同。 是否有单行 FFMPEG 命
我在 python3 类中有 2 个列表: self.keys = ["a","b","c","d"] self.values = [1,2,3,4] len(self.keys) == len(se
我有一个不同长度的数组列表,我想将它们组合成一个最大维度的矩阵,并在末尾填充零。例如(伪代码): combine( [1,2,3], [4,5]) [[1,2,3],[4,5,0]] 这是我目前的解决
例如,给定 i=5 和 n=8,我想生成 [0;0;0;0;1;0; 0;0]。具体来说,我想生成向量 v 以便: v = zeros(n,1); v(i) = 1; 有没有一种(合理的)方法可以在一
我是一名优秀的程序员,十分优秀!