1

マルチスレッドと複数のハードドライブを利用してパフォーマンスを向上させる、より複雑なプログラムのモデル プログラムを作成しました。データ サイズが非常に大きいため、すべてのデータをメモリに読み込むことは現実的ではないため、データはチャンクで読み込まれ、処理され、書き戻されます。このテスト プログラムはパイプライン設計を使用して、3 つの異なるスレッドで同時に読み取り、処理、および書き込みを行うことができます。読み取りと書き込みは別のハード ドライブに対して行われるため、読み取りと書き込みが同時に行われても問題はありません。ただし、マルチスレッドを使用するプログラムは、その線形バージョンよりも 2 倍遅く実行されるようです (コード内でも)。チャンクを実行した後に読み取りスレッドと書き込みスレッドが破棄されないようにしましたが、同期によって現在のバージョンよりもさらに遅くなったようです。私は何か間違ったことをしているのか、どうすればこれを改善できるのか疑問に思っていました。ありがとうございました。

i3-2100 @ 3.1ghz および 16GB RAM を使用してテスト済み。

#include <iostream>
#include <fstream>
#include <ctime>
#include <thread>

#define CHUNKSIZE 8192    //size of each chunk to process
#define DATASIZE 2097152  //total size of data

using namespace std;

int data[3][CHUNKSIZE];
int run = 0;
int totalRun = DATASIZE/CHUNKSIZE;

bool finishRead = false, finishWrite = false;

ifstream infile;
ofstream outfile;

clock_t starttime, endtime;

/*
    Process a chunk of data(simulate only, does not require to sort all data)
*/
void quickSort(int arr[], int left, int right) {

    int i = left, j = right;
    int tmp;
    int pivot = arr[(left + right) / 2];

    while (i <= j) {
        while (arr[i] < pivot) i++;
        while (arr[j] > pivot) j--;
        if (i <= j) {
            tmp = arr[i];
            arr[i] = arr[j];
            arr[j] = tmp;
            i++;
            j--;
        }
    };

    if (left < j) quickSort(arr, left, j);
    if (i < right) quickSort(arr, i, right);
}

/*
    Find runtime
*/
void diffclock(){
    double diff = (endtime - starttime)/(CLOCKS_PER_SEC/1000);
    cout<<"Total run time: "<<diff<<"ms"<<endl;
}

/*
    Read a chunk of data
*/
void readData(){

    for(int i = 0; i < CHUNKSIZE; i++){
        infile>>data[run%3][i];
    }
    finishRead = true;

}

/*
    Write a chunk of data
*/
void writeData(){

    for(int i = 0; i < CHUNKSIZE; i++){
        outfile<<data[(run-2)%3][i]<<endl;
    }
    finishWrite = true;
}

/*
    Pipelines Read, Process, Write using multithread
*/
void threadtransfer(){

    starttime = clock();

    infile.open("/home/pcg/test/iothread/source.txt");
    outfile.open("/media/pcg/Data/test/iothread/ThreadDuplicate.txt");

    thread read, write;

    run = 0;
    readData();

    run = 1;
    readData();
    quickSort(data[(run-1)%3], 0, CHUNKSIZE - 1);

    run = 2;
    while(run < totalRun){
        //cout<<run<<endl;
        finishRead = finishWrite = false;
        read = thread(readData);
        write = thread(writeData);
        read.detach();
        write.detach();
        quickSort(data[(run-1)%3], 0, CHUNKSIZE - 1);
        while(!finishRead||!finishWrite){}  //check if next cycle is ready.
        run++;
    }


    quickSort(data[(run-1)%3], 0, CHUNKSIZE - 1);
    writeData();

    run++;
    writeData();

    infile.close();
    outfile.close();

    endtime = clock();
    diffclock();
}

/*
    Linearly read, sort, and write a chunk and repeat.
*/
void lineartransfer(){

    int totalRun = DATASIZE/CHUNKSIZE;
    int holder[CHUNKSIZE];
    starttime = clock();

    infile.open("/home/pcg/test/iothread/source.txt");
    outfile.open("/media/pcg/Data/test/iothread/Linearduplicate.txt");

    run = 0;

    while(run < totalRun){

        for(int i = 0; i < CHUNKSIZE; i++) infile>>holder[i];
        quickSort(holder, 0, CHUNKSIZE - 1);
        for(int i = 0; i < CHUNKSIZE; i++) outfile<<holder[i]<<endl;
        run++;
    }

    endtime = clock();
    diffclock();
}

/*
    Create large amount of data for testing
*/
void createData(){
    outfile.open("/home/pcg/test/iothread/source.txt");

    for(int i = 0; i < DATASIZE; i++){
        outfile<<rand()<<endl;

    }
    outfile.close();
}



int main(){

    int mode=0;
    cout<<"Number of threads: "<<thread::hardware_concurrency()<<endl;
    cout<<"Enter mode\n1.Create Data\n2.thread copy\n3.linear copy\ninput mode:";
    cin>>mode;

    if(mode == 1) createData();
    else if(mode == 2) threadtransfer();
    else if(mode == 3) lineartransfer();

    return 0;
}
4

3 に答える 3

2

忙しくしないでください。これは貴重な CPU 時間を浪費し、残りの処理を遅くする可能性があります (言うまでもなく、これらのフラグが変更されるかどうかを推測できないため、コンパイラーはそれを無限ループに最適化できるため、そもそも正しくありません)。どちらもしないでくださいdetach()detach()と busy-waiting の両方を次のように置き換えますjoin()

while (run < totalRun) {
    read = thread(readData);
    write = thread(writeData);
    quickSort(data[(run-1)%3], 0, CHUNKSIZE - 1);
    read.join();
    write.join();
    run++;
}

quickSortグローバル設計に関しては、処理 ( ) 部分が読み取り/書き込み時間を超えることが予想されない場合は、グローバル変数を無視しても問題ないと思います。私は、メッセージ キューを使用して、さまざまなスレッド間でバッファーを渡すことができます (これにより、必要に応じて、同じタスクを並行して実行するか、異なるタスクを順番に実行するかのいずれかで、処理スレッドを追加できます)。そのようにしてください。

于 2013-07-31T23:14:52.010 に答える
1

Linux マシンでの使用時間を測定しclockているため、1 つのスレッドを実行しても複数のスレッドを実行しても、合計 CPU 時間は (ほぼ) 同じであると予想されます。

多分あなたはtime myprog代わりに使いたいですか?またはgettimeofday、時間を取得するために使用します (これにより、秒 + ナノ秒の時間が得られます [ただし、ナノ秒は最後の桁まで「正確」ではない可能性があります]。

endl編集:次に、ファイルへの書き込み時には使用しないでください。C++ ランタイムがオペレーティング システム コールであるファイルにアクセスしてフラッシュするため、処理が大幅に遅くなります。ほぼ確実に複数のスレッドから何らかの形で保護されているため、一度に 1 行の書き込みデータを同期的に実行する 3 つのスレッドがあります。ほとんどの場合、単一のスレッドを実行する場合のほぼ 3 倍の時間がかかります。また、3 つの異なるスレッドから同じファイルに書き込んではいけません。

于 2013-07-31T22:38:31.567 に答える
0

私が間違っている場合は修正してください。ただし、スレッド関数は基本的に、線形関数の 3 倍の作業を行う線形関数のようですか?

スレッド化されたプログラムでは、3 つのスレッドを作成し、readData/quicksort 関数を各スレッドで 1 回実行します (ワークロードを分散します)。しかし、プログラムでは、スレッド シミュレーションは実際には 3 回読み取り、3 回クイックソートし、3 回書き込みます。それぞれの 3 つすべてを実行するのにかかる時間を合計します。

于 2013-07-31T22:39:27.583 に答える