1

我已經創建了一個更復雜的程序的模型程序,它將利用多線程和多硬盤來提高性能。數據量太大,以至於讀取所有數據到內存中將不可行,因此數據將被讀取,處理並以塊的形式寫回。該測試程序使用流水線設計,能夠同時讀取,處理和寫出3個不同的線程。由於讀取和寫入是針對不同的硬盤驅動器,因此讀取和寫入同時沒有問題。但是,使用多線程的程序似乎比其線性版本運行速度慢2倍(也在代碼中)。我試圖讓讀寫線程在運行一個塊後不會被破壞,但同步似乎已經減慢了它的速度,甚至超過了當前的版本。我想知道如果我做錯了什麼或者我可以如何改善這一點。謝謝。並行程序沒有速度提升vs線性程序

使用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; 
} 

回答

1

因爲你是一個Linux機器上使用clock measuing的時候,我想到的是,總的CPU時間(大約)同您是否運行一個線程或多個線程。

也許你想用time myprog代替?或者使用gettimeofday獲取的時間(這將給你在幾秒鐘時間+納秒[雖然納秒可能不是「精確」到最後一位]

編輯: 下,不使用時endl寫入一個文件,它會讓速度變慢,因爲C++運行時會進入並刷新到文件中,這是一個操作系統調用,它幾乎肯定以某種方式受到多線程保護,因此您有三個線程正在執行寫入數據,一次只能同步一行,如果只運行一個線程,可能需要將近3倍,另外,不要從三個不同的線程寫入同一個文件 - 這種方式會變得很糟糕

+0

總的來說,運行時仍然比線性版慢得多。 – SpiralNemesis

+0

好的,看我的編輯。 –

+0

我明白了。感謝您的建議。時鐘似乎是問題所在。不看時間輸出,兩者似乎在相似的時間運行。 – SpiralNemesis

0

請糾正我,如果我我錯了,但看起來你的線程函數基本上是一個線性函數,它是你線性函數的3倍。

在一個線程化程序中,您將創建三個線程並在每個線程上運行一次readData/quicksort函數(分配工作負載),但在您的程序中,線程模擬實際上只是讀取三次,快速排序三次,寫三次,總共花三個時間完成。

+0

在threadtransfer函數中,While循環之外的函數調用用於設置/完成管道,因爲您需要先將數據讀入內存,然後才能在下一個循環中處理它。只有在while循環部分內,所有3個進程才能同時運行。 – SpiralNemesis

2

不要等待。這會浪費寶貴的CPU時間,並且可能會減慢其餘部分(更不用說編譯器可以將其優化爲無限循環,因爲它無法猜測這些標誌是否會改變,所以它甚至不是首要的)。也不要detach()。與join()更換兩個detach()和忙等待:

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

至於全球設計,好了,忽略了全局變量,我想如果你不希望在處理(quickSort)部分,它的其它合理超過了讀/寫時間。我會使用消息隊列在各個線程之間傳遞緩衝區(如果需要它可以添加更多的處理線程,可以並行執行相同的任務,也可以按順序執行不同的任務),但也許這是因爲我習慣於這樣做。