2017-04-22 19 views
6

Tôi có một chương trình khá để hiển thị hiệu suất của 2 chương trình tương tự, cả hai đều sử dụng 2 chuỗi để tính toán. Sự khác biệt cốt lõi là một sử dụng một biến toàn cầu, một sử dụng một đối tượng "mới", như sau:C++ sử dụng biến toàn cục cho thấy chậm hơn 100% so với con trỏ, khi sử dụng pthread?

#include<pthread.h> 
#include<stdlib.h> 
struct M{ 
    long a; 
    long b; 
}obj; 
size_t count=2000000000; 
void* addx(void*args){ 
    long*pl=(long*)args; 
    for(size_t i=0;i<count;++i) 
     (*pl)*=i; 
    return NULL; 
} 
int main(int argc,char*argv[]){ 
    pthread_t tid[2]; 
    pthread_create(&tid[0],NULL,addx,&obj.a); 
    pthread_create(&tid[1],NULL,addx,&obj.b); 
    pthread_join(tid[0],NULL); 
    pthread_join(tid[1],NULL); 
    return 0; 
} 

clang++ test03_threads.cpp -o test03_threads -lpthread -O2 && time ./test03_threads 

real 0m3.626s 
user 0m6.595s 
sys 0m0.009s 

Nó khá chậm, sau đó tôi sửa đổi obj để được tự động tạo ra (tôi mong đợi nó được thậm chí chậm hơn) :

#include<pthread.h> 
#include<stdlib.h> 
struct M{ 
    long a; 
    long b; 
}*obj;//difference 1 
size_t count=2000000000; 
void* addx(void*args){ 
    long*pl=(long*)args; 
    for(size_t i=0;i<count;++i) 
     (*pl)*=i; 
    return NULL; 
} 
int main(int argc,char*argv[]){ 
    obj=new M;//difference 2 
    pthread_t tid[2]; 
    pthread_create(&tid[0],NULL,addx,&obj->a);//difference 3 
    pthread_create(&tid[1],NULL,addx,&obj->b);//difference 4 
    pthread_join(tid[0],NULL); 
    pthread_join(tid[1],NULL); 
    delete obj;//difference 5 
    return 0; 
} 

clang++ test03_threads_new.cpp -o test03_threads_new -lpthread -O2 && time ./test03_threads_new 

real 0m1.880s 
user 0m3.745s 
sys 0m0.007s 

Thật ngạc nhiên 100% nhanh hơn trước đó. Tôi cũng đã thử g + + trên linux, cùng một kết quả. Nhưng làm thế nào để giải thích điều này? Tôi biết obj là biến toàn cầu, nhưng * obj vẫn là biến toàn cầu, chỉ được tạo động. Sự khác biệt cốt lõi là gì?

+0

Không thể tạo lại [test1] (http://ideone.com/jDOQ0b) (3,54s) và [test2] (http://ideone.com/C9R9ja) (3,55s). Cũng không nên '-O2' được đặt trước đường dẫn .cpp? – VTT

+0

Có thể có điều gì đó liên quan đến việc chia sẻ sai, nhưng người ta cho rằng chia sẻ sai là một vấn đề trong cả hai triển khai. – Unimportant

+0

Tệp thực thi của bạn có 32 hoặc 64 bit không? –

Trả lời

1

Tôi nghĩ rằng điều này thực sự là do chia sẻ sai, như không quan trọng được đề xuất.

Tại sao lại có sự khác biệt, bạn có thể hỏi?

Vì biến số count! Vì đây là biến số và loại cơ bản của size_t xảy ra là long cho bạn, trình biên dịch không thể tối ưu hóa nó đi (vì pl có thể trỏ đến count). Nếu count sẽ là int, vì quy tắc bí danh nghiêm ngặt, trình biên dịch có thể tối ưu hóa nó đi (hoặc đơn giản nó có thể là const size_t).

Vì vậy, mã được tạo phải đọc count mỗi lần trong vòng lặp.

Trong ví dụ đầu tiên, countobj cả hai biến toàn cầu, chúng được đặt gần nhau. Vì vậy, có khả năng cao là trình liên kết đưa các biến này vào cùng một dòng bộ nhớ cache. Vì vậy, viết thư tới obj.a hoặc obj.b sẽ làm mất hiệu lực dòng bộ nhớ cache của count. Vì vậy, CPU phải đồng bộ hóa số lần đọc của count.

Trong ví dụ thứ hai, obj được cấp phát trên heap, địa chỉ của nó sẽ đủ xa từ count, vì vậy chúng sẽ không chiếm cùng một dòng bộ nhớ cache. Không cần đồng bộ hóa cho count.

Các vấn đề liên quan