并行程序没有速度增加与线性程序

时间:2013-07-31 22:33:46

标签: c++ multithreading performance parallel-processing pipeline

我已经创建了一个更复杂程序的模型程序,它将利用多线程和多个硬盘来提高性能。数据大小太大,以至于无法将所有数据读入内存,因此数据将以块的形式读取,处理和写回。该测试程序使用流水线设计,能够在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;
}

3 个答案:

答案 0 :(得分:2)

不要忙碌等待。这浪费了宝贵的CPU时间,并且可能会减慢其余时间(更不用说编译器可以将其优化为无限循环,因为它无法猜测这些标志是否会发生变化,因此它首先不是正确的)。也不要detach()。将detach()和忙碌等待替换为join()

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

关于全局设计,好吧,忽略全局变量,我想如果您不希望处理(quickSort)部分超过读/写时间,则可以接受。我一个人会使用消息队列来传递各个线程之间的缓冲区(如果你需要它可以添加更多的处理线程,或者按顺序执行相同的任务或者按顺序执行不同的任务)但也许这是因为我习惯了这样做。

答案 1 :(得分:1)

由于您在Linux机器上使用clock测量时间,因此无论您运行一个线程还是多个线程,我都希望总CPU时间(大致)相同。

也许您想要使用time myprog代替?或者使用gettimeofday来获取时间(这会给你几秒钟的时间+纳秒[虽然纳秒可能不会“准确”到最后一位]。

编辑: 接下来,写入文件时不要使用endl。它减慢了很多东西,因为C ++运行时进入并刷新到文件,这是一个操作系统调用。它几乎可以肯定地受到多线程的保护,所以你有三个线程同时执行写数据,一行同步。只要运行单个线程,最有可能花费近3倍。另外,不要从三个不同的线程写入同一个文件 - 这会以某种方式变坏。

答案 2 :(得分:0)

如果我错了,请纠正我,但似乎你的线程函数基本上是一个线性函数做3倍线性函数的工作?

在线程程序中,您将创建三个线程并在每个线程上运行readData / quicksort函数一次(分配工作负载),但在您的程序中,似乎线程模拟实际上只是读取三次,快速排序三次,并写了三次,并总计完成所有这三次所需的时间。