Napisałem cztery różne programy, aby policzyć wszystkie słowa w dwóch plikach. Te cztery wersje wyglądają w większości tak samo. Pierwsze trzy wersje wykorzystują dwa wątki do zliczania, a same zamówienia trzech zdań są różne. Ostatnia wersja używa jednego wątku do zliczenia. Wymienię najpierw różne części każdej wersji i część wspólną, a następnie wynik każdej wersji i moje pytanie.Co kosztuje dodatkowy czas wykonania procedury w programie pthread?
inna część:
// version 1
count_words(&file1);
pthread_create(&new_thread, NULL, count_words, &file2);
pthread_join(new_thread, NULL);
// version 2
pthread_create(&new_thread, NULL, count_words, &file2);
count_words(&file1);
pthread_join(new_thread, NULL);
// version 3
pthread_create(&new_thread, NULL, count_words, &file2);
pthread_join(new_thread, NULL);
count_words(&file1);
// version 4
count_words(&file1);
count_words(&file2);
część wspólna (Włóż inną część do tej wspólnej części w celu stworzenia pełnej wersji)
#include <stdio.h>
#include <pthread.h>
#include <ctype.h>
#include <stdlib.h>
#include <time.h>
#define N 2000
typedef struct file_t {
char *name;
int words;
} file_t;
double time_diff(struct timespec *, struct timespec *);
void *count_words(void *);
// Usage: progname file1 file2
int main(int argc, char *argv[]) {
pthread_t new_thread;
file_t file1, file2;
file1.name = argv[1];
file1.words = 0;
file2.name= argv[2];
file2.words = 0;
// Insert different part here
printf("Total words: %d\n", file1.words+file2.words);
return 0;
}
void *count_words(void *arg) {
FILE *fp;
file_t *file = (file_t *)arg;
int i, c, prevc = '\0';
struct timespec process_beg, process_end;
struct timespec thread_beg, thread_end;
double process_diff, thread_diff;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &process_beg);
clock_gettime(CLOCK_THREAD_CPUTIME_ID, &thread_beg);
fp = fopen(file->name, "r");
for (i = 0; i < N; i++) {
while ((c = getc(fp)) != EOF) {
if (!isalnum(c) && isalnum(prevc))
file->words++;
prevc = c;
}
fseek(fp, 0, SEEK_SET);
}
fclose(fp);
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &process_end);
clock_gettime(CLOCK_THREAD_CPUTIME_ID, &thread_end);
process_diff = time_diff(&process_beg, &process_end);
thread_diff = time_diff(&thread_beg, &thread_end);
printf("count_words() in %s takes %.3fs process time and"
"%.3fs thread time\n", file->name, process_diff, thread_diff);
return NULL;
}
double time_diff(struct timespec *beg, struct timespec *end) {
return ((double)end->tv_sec + (double)end->tv_nsec*1.0e-9)
- ((double)beg->tv_sec + (double)beg->tv_nsec*1.0e-9);
}
UWAGA
- plik1 jest plik zawierający 10000 słów "słowa". plik2 jest kopią pliku1, utworzoną przez polecenie cp.
- Aby czas wykonania był wystarczająco długi, program wielokrotnie zlicza wyrazy. N to liczba pętli. Tak więc wynik nie jest dokładną liczbą całkowitych słów, ale mnoży się przez N.
- Nie kładź zbyt dużego nacisku na algorytm liczenia. Jestem tylko zaniepokojony czasem wykonania w tym przykładzie.
- Ważna informacja: Maszyna to procesor Intel® Celeron (R) 420 przy 1,60 GHz. jeden rdzeń. System operacyjny to Linux 3.2.0. Być może jeden rdzeń jest przyczyną tego dziwnego zjawiska, jak powiedzieli inni. Ale nadal chcę to rozgryźć.
Program liczy słowa i używa funkcji clock_gettime() do obliczenia czasu procesora procesora i czasu procesora rutyny count_words(), a następnie wyprowadzenia czasów i numeru słowa. Poniżej znajduje się wynik i mój komentarz z pytaniami. Będę bardzo wdzięczny, jeśli ktoś będzie mógł wyjaśnić powód, dla którego poświęca się dodatkowy czas.
// version 1
count_words() in file1 takes 2.563s process time and 2.563s thread time
count_words() in file2 takes 8.374s process time and 8.374s thread time
Total words: 40000000
Komentarz: Oryginalny wątek kończy count_words() i czeka na zgon nowego wątku. Kiedy count_words() działa w nowym wątku, nie następuje przełączanie kontekstu (ponieważ czas procesu == czas wątku). Dlaczego zajmuje to tyle czasu? Co dzieje się w count_words() w nowym wątku?
// version 2
count_words() in file1 takes 16.755s process time and 8.377s thread time
count_words() in file2 takes 16.753s process time and 8.380s thread time
Total words: 40000000
Komentarz: tutaj biegają równoległe dwie nitki. Przełącza kontekst, więc czas procesu> czas wątku.
// version 3
count_words() in file2 takes 8.374s process time and 8.374s thread time
count_words() in file1 takes 8.365s process time and 8.365s thread time
Total words: 40000000
Komentarz: Nowy wątek liczy się jako pierwszy i czeka na niego oryginalny wątek. Po połączeniu nowego wątku zaczyna się liczyć oryginalny wątek. Żadna z nich nie ma przełączania kontekstu, dlaczego tak dużo czasu zajęło, szczególnie liczenie po przyłączeniu nowego wątku?
// version 4
count_words() in file1 takes 2.555s process time and 2.555s thread time
count_words() in file2 takes 2.556s process time and 2.556s thread time
Total words: 40000000
Komentarz: Najszybsza wersja. Nie utworzono nowego wątku. Obie count_words() działa w jednym wątku.
Wersja porównawcza 1 + 2: Udostępnianie fałszywe? Być może to pomaga: http://stackoverflow.com/q/8331255/694576 – alk
@alk: Moja maszyna ma jeden rdzeń. Zgodnie z przyjętą odpowiedzią w cytowanym linku fałszywe udostępnianie jest wynikiem wielu rdzeni. Czy można to zrobić na pojedynczym rdzeniu? –