Eratosthenes的多线程筛 - 需要很长时间

时间:2013-03-04 19:51:38

标签: c multithreading performance pthreads sieve-of-eratosthenes

我正在尝试创建一个多线程的Eratosthenes Sieve

线程数默认设置为4,但用户可以将它们指定为命令行参数。

我试图在几个不同的线程中同时标记数组中所有素数的间隔。因此,包含0或1的数组将拆分为arrayElements / threadNumber。

每个线程都有一个指定的起始位置和数组的结束位置,以便检查其中的素数区间。

所以,例如,让我们假设您想要达到的数字是20,并且您有4个线程。线程0将从0开始并上升到20 / 4-1。接下来将从20/4 * threadNumber开始,然后上升到(20/4 * nextThreadNumber)-1,依此类推。

然后我必须检查找到的素数是否在其中一个线程的数组区域内。这是因为如果它是,那个素数不能被标记为nonprime。我遇到了一个问题,因为在超出第一个线程的边界之后,素数将被标记为nonprime,因为素数除了它自己。

如下所示,我发现startingPosition是否可以被素数整除。如果是的话,我将其设置为该线程" nonPrime seek"起始点,并从那里增加素数,将范围内的每个实例标记为非主要。如果它不是,那么我计算下一个非素数是什么(基于素数)并将其作为开始。

在所有这些结束时,它是你平常的#34;以primeNumber的间隔循环遍历数组,将每个实例标记为nonprime"。

长话短说,我必须使用最多32位整数(大约20亿左右)的数字。它可以在较小的数字下正常工作,但在对140万个数字进行一些基准测试后,需要13.4秒。 540万,需要37.3秒。 1000万,需要68秒。 对于20亿,它只是继续工作(我让它运行10分钟或更长时间),看不到尽头。

那么,我该如何改进我的代码呢?是什么导致它花了这么长时间?它似乎不比单线程实现快(我将线程参数设置为1表示单线程,并且1000万个数字需要56秒)

所以,这是代码,

定义maxNum 10483646

螺纹功能:

   int numThreads; //number of threads
    int innerCounter;
    int composite[maxNum];


//need to find all prime numbers up to unsigned 32 bit integer
//creating n threads, (start to 1/n -1) 0,  (1/n to 2/n -1) , (2/n to 3/n -1) until it's (n-1/n to n/n) are starting positions for looking for primes so threads aren't accessing same area
void* markPrimes(int i){
    //Prime number should be innerCounter
    //printf("Threaded process: %d\n", i);
    //starting position in array: (maxNum/threadNum) * i
    //ending position in array: ((maxNum/threadNum)) * (i+1) - 1
    int startingPosition;
    int compositeCounter;
    int firstNonPrime;
    int endingPosition;
    int primeInRange;


        startingPosition = (double)(maxNum/numThreads) * i;
        endingPosition = (double)(maxNum/numThreads) * (i+1)-1;
        if(i == numThreads-1){
            endingPosition = maxNum;
        }

        if(startingPosition <= innerCounter && innerCounter <= endingPosition){ //the prime number is in range, and should be ignored
            primeInRange = 1;
        }

        firstNonPrime = startingPosition%innerCounter;
        if(firstNonPrime != 0){
            int temp = innerCounter - firstNonPrime;
            firstNonPrime = temp + startingPosition;
        }else{
            firstNonPrime = startingPosition;
        }
        if(primeInRange == 1){
            firstNonPrime = innerCounter + innerCounter;
        }

    if(firstNonPrime <= endingPosition){


        for(compositeCounter = firstNonPrime; compositeCounter <= endingPosition; compositeCounter += innerCounter){

                        composite[compositeCounter] = 1;

                    }
    }
    return (void*)0;
}

现在主要功能包含算法的其余部分并创建线程:

int main(int argc, char** argv[]){

    clock_t start; //start time
    clock_t stop; //end time
    double total_time;
    int rc;
    int nextNum;
    int prevNum = 0;
    int i;
    int numPrimes;
    //unsigned int maxNum = INT_MAX; //maximum unsigned integer value to go up until
    //bit array for threads to check primes for
    for(i = 0; i < maxNum+1; i++){
        composite[i] = 0;
    }
    if(argc > 1){
        numThreads = atoi(argv[1]); //argument given for n number of threads
    }else{
        numThreads = 4; //default if no argument given is 4 threads
    }
    pthread_t threads[numThreads]; //array of threads
    start = clock(); //start timing

    //Sieve algorithm here! When prime found, spawn threads!
    int outerCounter = 1;
    while(outerCounter < sqrt(maxNum)){
        //searching numbers above the current for prime numbers

        for(innerCounter = outerCounter+1; innerCounter <= maxNum; innerCounter++){
            //not composite

            if(composite[innerCounter] == 0){
                //setting all multiples of innerCounter to 1, creating threads to split up the work!

                for(i = 0; i < numThreads; i++){

                    rc = pthread_create(&threads[i], NULL, markPrimes, (void*) i);

                    //Detecting Error
                    if(rc){
                        //perror("Thread creation error!");
                        //exit(-1);
                    }
                }
                for(i = 1; i < numThreads; i++){
                    pthread_join(threads[i], NULL);
                }
                outerCounter = innerCounter;
                numPrimes++;

            }
        }
    }

    stop = clock(); //stop timing
    total_time = (double)(stop - start) / CLOCKS_PER_SEC;


    printf("Time for threads: %.5f\n", total_time);
    printf("Number of primes: %d\n", numPrimes-1);

    return 0;
}

我提前感谢你们的耐心和帮助!

编辑:我必须使用pthreads

编辑2:我以How to sleep or pause a PThread in c on Linux为例尝试引导一些条件锁定和解锁。因为我基本上想要暂停和取消暂停素数的标记。我在我的线程函数中将while语句(使用lock和unlock语句)作为上面的组来发现启动/停止部分。当在带有lock / unlock语句的算法的内部if语句中找到素数时,我将int的标记设置为1,并在具有lock / unlock语句的if语句之外将该变量设置为0。

这就是我应该做的吗?

0 个答案:

没有答案