これは私の最初の投稿であり、私の母国語は英語ではありません。この投稿があなたにもたらす不便な点をお許しください。おそらくそれは少し長いので、私はあなたの忍耐を楽しみにしています。前もって感謝します!実行順序が異なるとPthreadプログラムのパフォーマンスが異なる
私はC言語コードスニペットを持っています。ジョブは2つのファイルの単語数を数えています。私はこの問題を解決するためにpthreadsを使用します。しかし、私はこれらの二つの文の順序を見つける
count_words(ARGV [1]);
pthread_create(& t1、NULL、count_words、(void *)argv [2]);
は、プログラムのパフォーマンスに影響します。これは、予想とは逆です。ここでは、コードは次のようになります。
#include <stdio.h>
#include <pthread.h>
#include <ctype.h>
#include <stdlib.h>
int total_words;
int main(int argc, char *argv[]) {
pthread_t t1;
void *count_words(void *);
if (argc != 3) {
printf("usage: %s file1 file2\n", argv[0]);
exit(1);
}
total_words = 0;
count_words(argv[1]); // program runs faster when executing this first
pthread_create(&t1, NULL, count_words, (void *)argv[2]);
pthread_join(t1, NULL);
printf("%5d: total words\n", total_words);
return 0;
}
void *count_words(void *f) {
char *filename = (char *)f;
FILE *fp;
int c, prevc = '\0';
if ((fp = fopen(filename, "r")) == NULL) {
perror(filename);
exit(1);
}
while ((c = getc(fp)) != EOF) {
if (!isalnum(c) && isalnum(prevc))
total_words++;
prevc = c;
}
fclose(fp);
return NULL;
}
パフォーマンス:
私は走行速度をテストするために、コマンドラインで「テストprogram_nameの」使用してプログラムを実行します。出力は次のとおり
場合、このような順序:
count_words(ARGV [1])。
pthread_create(& t1、NULL、count_words、(void *)argv [2]);
プログラムが高速に実行します:本当の0.014s
場合には、このような:
のpthread_create(& T1、NULL、count_words、(ボイド*)ARGV [2]);
count_words(argv [1]);
プログラムが遅い実行します:0.026s
本当の私が期待したもの:ケース1オン
は、プログラムは()最初count_word実行されます。カウントジョブを完了すると、pthread_create()が引き続き実行されます。その時点で、新しいスレッドは数える仕事をするのに役立ちます。したがって、新しいスレッドは、起点スレッドがジョブを完了した後にジョブを実行します。これは、並列実行ではなく順次実行です。ケース2の場合、プログラムは最初にpthread_create()を実行します。そのあとで2つのスレッドが並行してカウントします。だから私はケース2がケース1より速いと思う。しかし私は間違っている。ケース2は遅いです。誰も私にこれに関するいくつかの有用な情報を与えることができますか?
注
私はグローバル変数total_wordsにミューテックスのロックを入れていないことを無視してください。これは私が心配している部分ではありません。そしてこのプログラムはテスト用です。その不完全を許してください。私はいくつかの提案を読んだ後
編集以下は1
はサプリメントと改善です。
a)補足:プロセッサーはIntel®Celeron(R)CPU 420 @ 1.60GHzです。 1つのコア。
b)の改善:私はファイルを拡大)
1:私は、2つの変更を私の例を改善しています。 file1は2080651バイト(約2M)、file2はfile1のコピーです。
2)count_words()を変更しました。ファイルの終わりに達すると、fseek()を使用してfpを先頭に設定し、再度カウントします。繰り返すとCOUNT回カウントされます。定義COUNT以下20が変更されたコードです:
#define COUNT 20
// other unchanged codes ...
void *count_words(void *f) {
// other unchanged codes ...
int i;
for (i = 0; i < COUNT; i++) {
while ((c = getc(fp)) != EOF) {
if (!isalnum(c) && isalnum(prevc))
total_words++;
prevc = c;
}
fseek(fp, 0, SEEK_SET);
}
fclose(fp);
return NULL;
}
fast_versionの出力(count_word()最初)とslow_version(のpthread_create()最初):Ubuntuの@
管理者:〜$時間./fast_version FILE1 FILE2
12241560:合計言葉
本当0m5.057s
ユーザーが
を0m4.960s 210のsys 0m0.048s
管理者の@のubuntu:〜$時間./slow_version FILE1 FILE2
12241560:合計言葉
ユーザーが
0m7.280s本当0m7.636ssys 0m0.048s
"time progname file1 file2"コマンドを数回試しました。たぶん、毎回10分の1秒に何か違いがあります。しかし、違いはあまりありません。
編集2
私はいくつかのヒントに応じていくつかの実験を行った後にこの部分が追加された -
最初のスレッドが、それは実行だ完了後に2番目のスレッドを起動すると、そこにあります文脈の切り替えのオーバーヘッドはありません
--by user315052
実験は)(私はcount_wordを改善することである:
void *count_word(void *f) {
// unchanged codes
// ...
for (i = 0; i < COUNT; i++) {
while ((c = getc(fp)) != EOF) {
if (!isalnum(c) && isalnum(prevc))
total_words++;
prevc = c;
}
fseek(fp, 0, SEEK_SET);
printf("from %s\n", filename); // This statement is newly added.
}
// unchanged codes
// ...
}
は声明 "(%sの\ nからのprintf" 追加 "ファイル名);" ので、私はどのファイル(またはスレッド)を伝えることができますその時に走っています。高速版の出力は「file1」から20回、「file2」から20回、slow版は「from file1」と「file2」が混在して出力されます。
コンテキストの切り替えがないため、高速版の方が高速です。しかし実際、count_word()が終了した後、元のスレッドは死んでいませんでしたが、新しいスレッドを作成し、終了するのを待っていました。新しいスレッドが実行されているときにコンテキストの切り替えはないのですか?私は画面をよく見て、 "file2"の印刷速度が "file1"よりも明らかに遅いことを発見しました。どうして?それはファイル2から数えたときにコンテクストの切り替えが起こったからですか?
低速版では、 "file1"と "file2"の印刷速度が、高速バージョンの "file2"の印刷速度よりもさらに遅いことが出力からわかります。高速のバージョンでは、スレッドの1つがジョブを終了して待っているだけでコンテキストの切り替えはそれほど重くはありません。
私は主な理由は、高速版は、軽くて簡単な文脈の切り替えが遅いバージョンと考えていると思います。しかし、「印刷速度」は私の見解であり、それほど厳しくはないかもしれません。だから私はそれについては分かりません。
あなたはどのマシンを実行していますか?あなたは実際に2つのコアを持っていますか? – jxh
'total_words ++ 'をコメントアウトするとどうなりますか?相対的なタイミングは同じままですか? – NPE
時間がかなり短いです - 正確にどのように測定していますか?非常に大きな入力で実行する方がよい。 –