몬테카를로 알고리즘의 멀티 스레드 버전을 구현하려고합니다.pthread가있는 실제 가속이 없음
#define _POSIX_C_SOURCE 200112L
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <time.h>
#include <math.h>
#include <semaphore.h>
#include <errno.h>
#include <stdbool.h>
#include <string.h>
#define MAX_THREADS 12
#define MAX_DOTS 10000000
double sum = 0.0;
sem_t sem;
void reset() {
sum = 0.0;
}
void* check_dot(void* _iterations) {
int* iterations = (int*)_iterations;
for(int i = 0; i < *iterations; ++i) {
double x = (double)(rand() % 314)/100;
double y = (double)(rand() % 100)/100;
if(y <= sin(x)) {
sem_wait(&sem);
sum += x * y;
sem_post(&sem);
}
}
return NULL;
}
void* check_dots_advanced(void* _iterations) {
int* iterations = (int*)_iterations;
double* res = (double*)malloc(sizeof(double));
for(int i = 0; i < *iterations; ++i) {
double x = (double)(rand() % 314)/100;
double y = (double)(rand() % 100)/100;
if(y <= sin(x)) *res += x * y;
}
pthread_exit((void*)res);
}
double run(int threads_num, bool advanced) {
if(!advanced) sem_init(&sem, 0, 1);
struct timespec begin, end;
double elapsed;
pthread_t threads[threads_num];
int iters = MAX_DOTS/threads_num;
for(int i = 0; i < threads_num; ++i) {
if(!advanced) pthread_create(&threads[i], NULL, &check_dot, (void*)&iters);
else pthread_create(&threads[i], NULL, &check_dots_advanced, (void*)&iters);
}
if(clock_gettime(CLOCK_REALTIME, &begin) == -1) {
perror("Unable to get time");
exit(-1);
}
for(int i = 0; i < threads_num; ++i) {
if(!advanced) pthread_join(threads[i], NULL);
else {
void* tmp;
pthread_join(threads[i], &tmp);
sum += *((double*)tmp);
free(tmp);
}
}
if(clock_gettime(CLOCK_REALTIME, &end) == -1) {
perror("Unable to get time");
exit(-1);
}
if(!advanced) sem_destroy(&sem);
elapsed = end.tv_sec - begin.tv_sec;
elapsed += (end.tv_nsec - begin.tv_nsec)/1000000000.0;
return elapsed;
}
int main(int argc, char** argv) {
bool advanced = false;
char* filename = NULL;
for(int i = 1; i < argc; ++i) {
if(strcmp(argv[i], "-o") == 0 && argc > i + 1) {
filename = argv[i + 1];
++i;
}
else if(strcmp(argv[i], "-a") == 0 || strcmp(argv[i], "--advanced") == 0) {
advanced = true;
}
}
if(!filename) {
fprintf(stderr, "You should provide the name of the output file.\n");
exit(-1);
}
FILE* fd = fopen(filename, "w");
if(!fd) {
perror("Unable to open file");
exit(-1);
}
srand(time(NULL));
double worst_time = run(1, advanced);
double result = (3.14/MAX_DOTS) * sum;
reset();
fprintf(fd, "Result: %f\n", result);
for(int i = 2; i <= MAX_THREADS; ++i) {
double time = run(i, advanced);
double accel = time/worst_time;
fprintf(fd, "%d:%f\n", i, accel);
reset();
}
fclose(fd);
return 0;
}
그러나, 나는 스레드의 수를 증가와 함께 실제 가속을 볼 수 없습니다 (그리고 내가 사용하고 무엇을 check_dot() 함수를 중요하지 않습니다) : 여기 내 코드입니다. 내가 인텔 코어 i7-3517u 내 노트북에이 코드를 실행하기 위해 노력했다 (lscpu는 4 개 독립적 인 CPU가 있다고 말한다) 그리고 스레드의 수처럼 보이는 정말 내 프로그램의 실행 시간에 영향을 미친다 :
Number of threads: 1, working time: 0.847277 s
Number of threads: 2, working time: 3.133838 s
Number of threads: 3, working time: 2.331216 s
Number of threads: 4, working time: 3.011819 s
Number of threads: 5, working time: 3.086003 s
Number of threads: 6, working time: 3.118296 s
Number of threads: 7, working time: 3.058180 s
Number of threads: 8, working time: 3.114867 s
Number of threads: 9, working time: 3.179515 s
Number of threads: 10, working time: 3.025266 s
Number of threads: 11, working time: 3.142141 s
Number of threads: 12, working time: 3.064318 s
을
적어도 4 개의 첫 번째 값 (실행되는 스레드가 적을수록 스레드가 많을수록)이 실행 시간과 작업 스레드 수 사이에 일종의 선형 의존성이 있어야한다고 생각합니다. 그러나 여기에는 꽤 동일한 시간 값이 있습니다. . 그것은 내 코드에서 실제 문제입니까 아니면 너무 까다 롭습니다.
멀티 스레딩은 매우 비쌉니다. 동시성이 처리량을 속도를 향상시켜 이점이 비용보다 중요한 것으로 생각할 수있는 심오한 알고리즘 및 수학적 이유가있는 경우에만 가치가 있습니다. –
코어 i7-3517u는 듀얼 코어 (하이퍼 스레딩 기능 포함)입니다. 이는 2 개의 스레드에 대해 2 개의 코어를 사용하고 4 개의 스레드로 코어의 자원을 공유하는 "코어 당 2 개의 스레드"를 얻는다는 것을 의미합니다. 4 개가 넘는 스레드는 시간 낭비입니다 (스레드 전환 오버 헤드 만 얻을 수 있습니다). – Brendan
@ EOF,'sum '에 대한 액세스가 왜 동기화되지 않았는지 설명하면 감사하겠습니다. 여기 세마포어를 사용합니다. 그렇죠? – kasom