- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在用 C 语言试验线程,但我对某些结果感到困惑。
我有以下循环:
for(size_t i=0;i<1000000000;i++){
a++;
}
它增加一个全局变量
a
.我用 6 个变量完成了这个,
a
至
e
.
main
中连续增加变量。 :
#include<stdio.h>
#include<pthread.h>
size_t a,b,c,d,e,f;
int main(void){
for(size_t i=0;i<1000000000;i++){
a++;
}
for(size_t i=0;i<1000000000;i++){
b++;
}
for(size_t i=0;i<1000000000;i++){
c++;
}
for(size_t i=0;i<1000000000;i++){
d++;
}
for(size_t i=0;i<1000000000;i++){
e++;
}
for(size_t i=0;i<1000000000;i++){
f++;
}
size_t abcdef=a+b+c+d+e+f;
printf("%zu\n",abcdef);
return 0;
}
然后,当用
time
测试程序时,得到以下结果:
6000000000
real 0m11.450s
user 0m11.446s
sys 0m0.000s
我希望使用 pthreads 的结果会快很多:
#include<stdio.h>
#include<pthread.h>
size_t a,b,c,d,e,f;
void *t1(void *args){
for(size_t i=0;i<1000000000;i++){
a++;
}
return NULL;
}
void *t2(void *args){
for(size_t i=0;i<1000000000;i++){
b++;
}
return NULL;
}
void *t3(void *args){
for(size_t i=0;i<1000000000;i++){
c++;
}
return NULL;
}
void *t4(void *args){
for(size_t i=0;i<1000000000;i++){
d++;
}
return NULL;
}
void *t5(void *args){
for(size_t i=0;i<1000000000;i++){
e++;
}
return NULL;
}
void *t6(void *args){
for(size_t i=0;i<1000000000;i++){
f++;
}
return NULL;
}
int main(void){
pthread_t p1,p2,p3,p4,p5,p6;
pthread_create(&p1,NULL,t1,NULL);
pthread_create(&p2,NULL,t2,NULL);
pthread_create(&p3,NULL,t3,NULL);
pthread_create(&p4,NULL,t4,NULL);
pthread_create(&p5,NULL,t5,NULL);
pthread_create(&p6,NULL,t6,NULL);
pthread_join(p1,NULL);
pthread_join(p2,NULL);
pthread_join(p3,NULL);
pthread_join(p4,NULL);
pthread_join(p5,NULL);
pthread_join(p6,NULL);
size_t abcdef=a+b+c+d+e+f;
printf("%zu\n",abcdef);
return 0;
}
然而,结果却出乎意料:
6000000000
real 0m14.521s
user 1m26.048s
sys 0m0.014s
不仅实际时间更大,我预计会更低,而且用户时间超过 1 分钟,我没有等一分钟。
最佳答案
您在这里遇到的问题是由于缓存一致性。
在现代处理器中,单个内核一次可以访问的实际最小内存量是一个完整的高速缓存行,在许多现代处理器上是 64 字节。这意味着每个变量的每次增量都会读取 64 个字节,其中 8 个字节会针对增量进行修改。其他 56 个字节只是随手可用。
但是,如果其他任何字节需要由另一个内核修改,它们必须使用缓存一致性协议(protocol)来确保它们不会破坏彼此的内存。当写入缓存行时,它将被标记为已修改,并且每个其他缓存都必须将其标记为无效并重新加载以再次使用它。
当您在代码中将变量定义为:
size_t a,b,c,d,e,f;
它们都作为一个连续的 block 在内存中排列,最终将小于一个完整的高速缓存行。这意味着每个线程都在争夺一个 64 字节的内存块,并且在获得它之前无法继续前进。这使得实际执行是串行的,即使多个内核可能同时执行代码。
$ time ./test
6000000000
real 0m22.526s
user 0m22.391s
sys 0m0.000s
$ time ./test1
6000000000
real 0m13.094s
user 1m7.797s
sys 0m0.047s
我的 pthreads 测试实际上更快。我怀疑这是由于我的 CPU 使用了超线程,它实际上在同一个内核上运行两个线程,它们共享同一个缓存行,所以没有争用。
size_t a __attribute__ ((aligned (64)));
size_t b __attribute__ ((aligned (64)));
size_t c __attribute__ ((aligned (64)));
size_t d __attribute__ ((aligned (64)));
size_t e __attribute__ ((aligned (64)));
size_t f __attribute__ ((aligned (64)));
结果如下:
$ time ./test2
6000000000
real 0m2.665s
user 0m15.281s
sys 0m0.016s
它的速度更快!
关于带线程的代码比没有线程花费的时间更长,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68005531/
我一直在读一本分配给类(class)的书,它提到数组访问需要 O(1) 时间。我意识到这非常快(也许尽可能快),但是如果您有一个循环必须多次引用它,那么分配一个临时变量以在数组中查找值有什么好处吗?或
我一直试图找出为什么这个查询花了这么长时间。以前,它的执行时间约为 150 毫秒到 200 毫秒,但现在需要 25 秒或更长时间。这是从昨晚到今天之间的事。唯一改变的就是将数据添加到表中。 根据下面的
我有一个 ng repeat 重复数据。 - data.image(src)部分为null,src=null的不再重复。 我用一个简单的 ng-if 解决了它。
我有一个包含大量测试的 Laravel 项目。我正在使用 pcov 来计算代码覆盖率,大约需要 4 分钟。但是 pcov 不支持分支覆盖,所以我决定使用 xdebug。 使用 xdebug 测试执行,
我已经被这个问题困扰了一段时间了,我被难住了。 Automapper 需要 4 秒来映射 19 个对象。在我的机器(24GB 内存,3.6Ghz i7)上,该操作应该花费毫秒或纳秒。 这是映射调用。
我有一个包含大量测试的 Laravel 项目。我正在使用 pcov 来计算代码覆盖率,大约需要 4 分钟。但是 pcov 不支持分支覆盖,所以我决定使用 xdebug。 使用 xdebug 测试执行,
我在机器 A 上有一个 java 进程通过 TCP 与机器 B 上的 Tomcat 通信。 TCP 连接(只是 syn-syn/ack 交换)始终需要 100 毫秒的数量级,而 ping 请求需要 1
我做了一项任务,从 sqlserver 获取超过 200 万条记录并将它们填充到 Asp.net GridView 中。 问题是,查询需要超过 2 分钟才能获得记录,而我的查询现在已经完全优化。 当我
我希望将 165 秒变成 2:40 而不是 0:2:45 函数需要能够适应秒值的大小。 我知道有无数种方法可以做到这一点,但我正在寻找一种干净的方法来做到这一点,除了 jQuery 之外没有任何外部库
我是一名优秀的程序员,十分优秀!