🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

ソート

複数のデータを、順序性に従って並べ替えること。 データ処理を行う際に頻繁に用いられ、多くのアルゴリズムが存在します。速度、容量、複雑さなどに違いがあり、高速性に特化したものにクイックソートがあります。

Q&A

解決済

2回答

1740閲覧

C言語のpthreadについて

Tinasp

総合スコア4

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

ソート

複数のデータを、順序性に従って並べ替えること。 データ処理を行う際に頻繁に用いられ、多くのアルゴリズムが存在します。速度、容量、複雑さなどに違いがあり、高速性に特化したものにクイックソートがあります。

0グッド

1クリップ

投稿2021/02/01 15:34

C言語においてpthreadを用いてクイックソートの高速化を勉強中なのですが、疑問点があるのでどうかご教授お願いします。

高速化するためにいろいろとスレッドを作る場所や、*func_thread()で行う処理などを考えました。初めは再帰関数が呼び出されているところでスレッドを作れば高速化できると考えていました。しかし、結局以下のように最初のquick_sort_pthread()の呼び出しのところでスレッドを作ったら高速化できました。どうして下のようなコードで逐次処理に比べ高速化したのかがわかりません。別のスレッドでただquick_sort_pthread()を動かしているだけに見えます。なぜ高速化したのか、これが最善の高速化なのかが分からなくてもやもやしてます。絶対にこれより良いpthreadを用いた高速化ができると思うのですが。

どうかご教授お願いします。

#include <stdio.h> #include<stdlib.h> #include <unistd.h> #include <omp.h> #include<time.h> #include<sys/time.h> #include<pthread.h> int partition(int[],int,int); void *func_thread(void *p); void quick_sort_pthread(int[],int,int); int *array = NULL; const int data_num = 100000; int left; int right; int pivot; void *func_thread(void *p){ if (left < right) { pivot = partition(array, left, right); quick_sort_pthread(array, left, pivot-1); quick_sort_pthread(array, pivot+1, right); } } void quick_sort_pthread(int array[], int left, int right) { int pivot; if (left < right) { pivot = partition(array, left, right); quick_sort_pthread(array, left, pivot-1); quick_sort_pthread(array, pivot+1, right); } } int partition (int array[], int left, int right) { int i, j, pivot; i = left; j = right + 1; pivot = left; do { do { i++; } while (array[i] < array[pivot]); do { j--; } while (array[pivot] < array[j]); if (i < j) { swap(&array[i], &array[j]); } } while (i < j); swap(&array[pivot], &array[j]); return j; } void Shuffle(int *array, int n) { int i,j,t; srand(1); for (i = 0; i < n; i++) { j = rand() % n; t = array[i]; array[i] = array[j]; array[j] = t; } } int main (void) { int i; struct timeval time_start, time_end,start,end; pthread_t pthread1; pthread_t pthread2; int thread_id1=1; int thread_id2=2; array= (int *)malloc(sizeof(int)*data_num); for(i=0; i<data_num; i++){ array[i]=i; } Shuffle(array, data_num);//配列をシャッフル gettimeofday(&time_start, NULL); pthread_create( &pthread1, NULL, &func_thread, &thread_id1); pthread_create( &pthread2, NULL, &func_thread, &thread_id2); quick_sort_pthread(array,0,data_num); pthread_join(pthread1, NULL); pthread_join(pthread2, NULL); gettimeofday(&time_end, NULL); printf("Serialtime = %.3lf ms\n", ((time_end.tv_sec - time_start.tv_sec) + (time_end.tv_usec - time_start.tv_usec)*1.0E-6)*1000); return 0; }

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

y_waiwai

2021/02/01 23:09

なにがどういうふうに高速化したという話でしょうか。 具体的なデータが提示されないでは答えようもありません
angel_p_57

2021/02/02 02:11

指摘にある、pthread_create で作り出したスレッドが実質何もしない、というのもありますが、そもそも partition() がバグってるので正しく動く保証がないです。( i++ や j-- にストッパーがないので配列外まで行く可能性がある ) まずは正しく動くコードかどうかを確かめてからです。
Tinasp

2021/02/02 06:49

10万個のランダムな値が入っている配列をソートするプログラムなのですが、逐次処理の場合は平均17.144ms、上のコードの場合は12.965msという結果になりました。
guest

回答2

0

quick_sort_pthread()の呼び出しのところでスレッドを作ったら高速化できました。

高速化できた、というのは何かの間違いではないでしょうか。
main()で作っている2つのスレッドは、何もしないで一瞬で終了しているはずです。(グローバルのleftrightが0のまま変更されないため)

投稿2021/02/02 01:26

int32_t

総合スコア21679

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

ベストアンサー

マルチコア

現代のコンピュータは演算コアを複数持っている場合がそれなりにあります。 これを効果的に活用するには演算を分割して各コアで実行させる必要があり、それがマルチスレッドで性能が上がる理由です。

ハイパースレッディング

一部の製品はハイパースレッディングというひとつのコアを疑似的に二つに見せかける技術を使っています。 無いよりは有ったほうがマルチスレッドの性能はかなり高くなりますが、そうは言っても疑似的なものなので二つのコアよりは低い性能です。

時分割マルチスレッド

スレッドの割り当ては OS が管理しており、ごく短い時間で複数のスレッドを切り替えながら実行することでたくさんのスレッドをひとつのコアで実行できるようになっています。

OS を起動しただけでも数千単位のスレッドが走っている状態になるのが普通ですが、実際には何かのイベントが起きるまで待機状態にあるだけなので演算性能を (それほど) 圧迫することはありません。

スレッドとコアの割り当て

上述の理由により、スレッドをたくさん作ることは出来ますが、あまりたくさん作ってもひとつのコア上で複数のスレッドが走っている状況では全体の演算性能は上がりません。 コアの数よりたくさんスレッドを作る意味はあまりないどころかスレッド切り替えのコストのために性能が下がる可能性が高いです。

スレッド生成コスト

プログラムを書くときに気を付けなければならないのは、スレッドの生成・解体のコストがかなり大きいということです。 頻繁にスレッドを作ったり解体するのは性能の足を引っ張ることになります。

スレッドプール

よく使われる一般的なテクニックが「スレッドプール」です。 事前に一定数のスレッドを生成して、そこに処理すべきデータを「割り当て (アタッチ)」することでスレッドの数を効果的な一定数に保ちながら、スレッドの生成・解体コストも抑えることができます。

ただし、処理の割り当てを管理するのが煩雑になりますし、割り当て管理の演算で演算コストが増えるようでもそれはそれで全体の演算性能の足を引っ張るわけです。

質問者のコード

質問者の提示しているコードでは、もし再帰のたびにスレッドを生成するのだとスレッドの数が爆発的に増えます。 先述のように、コアの数を超えるスレッドは高速化に寄与しません。 スレッド生成のコストが並列演算の恩恵を大幅に超えてしまいます。

スレッドを二個に限るという割り切りで (シングルスレッドよりは) 性能を出しつつ、マルチスレッドの問題を踏まないような構成に結果的になっているのでそれなりに良い性能が出たのでしょう。

投稿2021/02/02 01:04

SaitoAtsushi

総合スコア5684

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Tinasp

2021/02/02 08:39

回答ありがとうございます。回答者様のヒントを元に調べたところ、スレッドを用いた高速化の具体的な方法が見えてきました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問