การทำขนานกับโดเมน 2D โดยใช้ MPI

ดูเหมือนว่าฉันไม่สามารถใช้งานอัลกอริธึมนี้ได้ และฉันเชื่อว่าอาจเป็นเพราะ 'สภาพการแข่งขัน' แต่ฉันอาจผิด:

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include <mpi.h>

#define BILLION     1000000000L

double f(double, double);
double g(double, double);

int main(int argc, char** argv){
    FILE *myA, *myB;    
    int rank, size;
    MPI_Init(NULL, NULL);
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
    MPI_Comm_size(MPI_COMM_WORLD, &size);

    if (rank == 0){
        myA = fopen("myA.py", "w");
        myB = fopen("myB.py", "w");
    }

    int m = 255;            // Max number of x values
    int n = 255;            // Max number of y values
    int Tmax = 5;//10000;   // Max number of time steps

    double a = 0, b = 2.5;      // starting and ending points along x-axis
    double c = 0, d = 2.5;      // starting and ending points along y-axis

    double dx = (b - a)/m;      // x partition width
    double dy = (d - c)/n;      // y partition width
    double dt = 1.;             // t partition width

    double D_u = 0.00002;   // diffusion coefficient
    double alpha_u = D_u*dt/(dx*dx), gamma_u = D_u*dt/(dy*dy), beta_u = 1 - 2*alpha_u - 2*gamma_u; // coeffs for fwd Euler method

    double D_v = 0.00001;   // diffusion coefficient
    double alpha_v = D_v*dt/(dx*dx), gamma_v = D_v*dt/(dy*dy), beta_v = 1 - 2*alpha_v - 2*gamma_v; // coeffs for fwd Euler method

    // Parameters:
    double F = 0.040;
    double K = 0.063;

    // Domain:
    double u[m+1][n+1];     // soln to the diffusion equation
    double utmp[m+1][n+1];  // temp storage

    double v[m+1][n+1];     // soln to the diffusion equation
    double vtmp[m+1][n+1];  // temp storage

    int i, j, k;

    // initialize time variables
    struct timespec begin, end;
    double time_lapsed;

    // seed rand
    srand(time(NULL));
    double noise;
    double lowest = -1./100.;
    double highest = 1./100.;
    double range = (highest - lowest);

    // divide up the domain evenly among groups
    int Np = floor((double)m/size);  // Number of rows per processor
    //int res = m % size/2;  // in case extra row in subgroup
    //int bigres = n % 2;  // in case extra row overall

    int istart = rank*Np;
    int iend;

    if (rank == 0){
        istart = 1;
        iend = (rank + 1)*Np;
    }

    else if (rank == size-1){
        iend = m;
    }

    else {
        iend = (rank + 1)*Np;
    }

    if (rank == 0){
        fprintf(myA,"from numpy import array\n");
        fprintf(myA,"\ndef myAi():\n");
        fprintf(myA,"\treturn array([ ");
        clock_gettime(CLOCK_MONOTONIC, &begin); // start timing u
    }

    // Initialization for u:
    for (i = 0; i <= m; i += 1){
        if (rank == 0){
            fprintf(myA,"[ ");
        }
        for (j = 0; j <= n; j += 1){
            // create square
            if ((i >= 117 && i <= 137) && (j >= 117 && j <= 137)){
                noise = (lowest + range*rand()/(RAND_MAX + 1.0));
                if (abs(noise) > 0.01){
                    printf("noise: %f\n",noise);
                }

                utmp[i][j] = 1./2 + noise*(1./2.);//f(a + i*dx,c + j*dy);
                u[i][j] = utmp[i][j];
            }
            else{
                utmp[i][j] = 1.;//f(a + i*dx,c + j*dy);
                u[i][j] = utmp[i][j];
            }
            if (rank == 0){

                // print matrix entries
                if (j != n){
                    fprintf(myA,"%f, ",utmp[i][j]);
                }
                else{
                    fprintf(myA,"%f ",utmp[i][j]);
                }
            }
        }
        if (rank == 0){
            if (i != m){
                fprintf(myA,"],\n");
            }
            else{
                fprintf(myA,"]");
            }
        }
    MPI_Bcast(&u[i][0],(n+1),MPI_DOUBLE,0,MPI_COMM_WORLD);
    MPI_Bcast(&utmp[i][0],(n+1),MPI_DOUBLE,0,MPI_COMM_WORLD);
    }

    if (rank == 0){
        fprintf(myA,"])\n");
        clock_gettime(CLOCK_MONOTONIC, &end);
        time_lapsed = (end.tv_sec - begin.tv_sec) + (double)(end.tv_nsec - begin.tv_nsec)/BILLION;
        printf("\nprint 'Time to initialize u:',%f,'seconds.'\n",time_lapsed);

        clock_gettime(CLOCK_MONOTONIC, &begin); // start timing v

        fprintf(myB,"from numpy import array\n");
        fprintf(myB,"\ndef myBi():\n");
        fprintf(myB,"\treturn array([ ");
    }

    // Initialization for v:
    for (i = 0; i <= m; i += 1){
        if (rank == 0){
            fprintf(myB,"[ ");
        }
        for (j = 0; j <= n; j += 1){
            // create square
            if ((i >= 117 && i <= 137) && (j >= 117 && j <= 137)){
                noise = (lowest + range*rand()/(RAND_MAX + 1.0));
                vtmp[i][j] = 1./4 + noise*(1./4.);//g(a + i*dx,c + j*dy);
                if (abs(noise) > 0.01){
                    printf("noise: %f\n",noise);
                }

                v[i][j] = vtmp[i][j];
            }
            else{
                vtmp[i][j] = 0.;//g(a + i*dx,c + j*dy);
                v[i][j] = vtmp[i][j];
            }

            if (rank == 0){
                // print matrix entries
                if (j != n){
                    fprintf(myB,"%f, ",vtmp[i][j]);
                }
                else{
                    fprintf(myB,"%f ",vtmp[i][j]);
                }
            }
        }
        if (rank == 0){
            if (i != m){
                fprintf(myB,"],\n");
            }
            else{
                fprintf(myB,"]");
            }
        }
    MPI_Bcast(&v[i][0],(n+1),MPI_DOUBLE,0,MPI_COMM_WORLD);
    MPI_Bcast(&vtmp[i][0],(n+1),MPI_DOUBLE,0,MPI_COMM_WORLD);
    }

    if (rank == 0){
        fprintf(myB,"])\n");
        clock_gettime(CLOCK_MONOTONIC, &end);
        time_lapsed = (end.tv_sec - begin.tv_sec) + (double)(end.tv_nsec - begin.tv_nsec)/BILLION;
        printf("\nprint 'Time to initialize v:',%f,'seconds.'\n",time_lapsed);
    }

    MPI_Barrier(MPI_COMM_WORLD);
    // All together now...

    if (iend > m/2){
        if (rank == size-1){
            for (k = 1; k <= Tmax; k++){
                i = istart;
                for (i = istart; i < iend-1; i++){
                    for (j = 1; j < n-1; j++){

                        // Do usual computation with u_i,j = alpha * (u_i-1,j + u_i+1,j) + 
                        u[i][j] = alpha_u*(utmp[i-1][j] + utmp[i+1][j]) + beta_u*utmp[i][j] + gamma_u*(utmp[i][j-1] + utmp[i][j+1]) - u[i][j]*v[i][j]*v[i][j] + F*(1. - u[i][j]);
                        v[i][j] = alpha_v*(vtmp[i-1][j] + vtmp[i+1][j]) + beta_v*vtmp[i][j] + gamma_v*(vtmp[i][j-1] + vtmp[i][j+1]) + u[i][j]*v[i][j]*v[i][j] - (F+K)*v[i][j];
                    }

                    // left-right Periodic boundary conditions:
                    u[i][n-1] = alpha_u*(utmp[i-1][n-1] + utmp[i+1][n-1]) + beta_u*utmp[i][n-1] + gamma_u*(utmp[i][n-2] + utmp[i][0]) - u[i][n-1]*v[i][n-1]*v[i][n-1] + F*(1. - u[i][n-1]);
                    v[i][n-1] = alpha_v*(vtmp[i-1][n-1] + vtmp[i+1][n-1]) + beta_v*vtmp[i][n-1] + gamma_v*(vtmp[i][n-2] + vtmp[i][0]) + u[i][j]*v[i][n-1]*v[i][n-1] - (F+K)*v[i][n-1];
                }

                // top-bottom Periodic Boundary conditions:
                for (j = 1; j < n-1; j++){
                    u[iend-1][j] = alpha_u*(utmp[iend-2][j] + utmp[0][j]) + beta_u*utmp[iend-1][j] + gamma_u*(utmp[iend-1][j-1] + utmp[iend-1][j+1]) - u[iend-1][j]*v[iend-1][j]*v[iend-1][j] + F*(1. - u[iend-1][j]);
                    v[iend-1][j] = alpha_v*(vtmp[iend-2][j] + vtmp[0][j]) + beta_v*vtmp[iend-1][j] + gamma_v*(vtmp[iend-1][j-1] + vtmp[iend-1][j+1]) + u[iend-1][j]*v[iend-1][j]*v[iend-1][j] - (F+K)*v[iend-1][j];
                }

                // top-bottom & left-right Periodic Boundary Conditions
                u[iend-1][n-1] = alpha_u*(utmp[iend-2][n-1] + utmp[0][n-1]) + beta_u*utmp[iend-1][n-1] + gamma_u*(utmp[iend-1][n-2] + utmp[iend-1][0]) - u[iend-1][n-1]*v[iend-1][n-1]*v[iend-1][n-1] + F*(1. - u[iend-1][n-1]);
                v[iend-1][n-1] = alpha_v*(vtmp[iend-2][n-1] + vtmp[0][n-1]) + beta_v*vtmp[iend-1][n-1] + gamma_v*(vtmp[iend-1][n-2] + vtmp[iend-1][0]) + u[iend-1][n-1]*v[iend-1][n-1]*v[iend-1][n-1] - (F+K)*v[iend-1][n-1];

                i = istart;
                for (i = istart; i <= iend; i++){   //istart; i <= iend; i++){
                    for (j = 0; j <= n; j++){
                        utmp[i][j] = u[i][j];
                        vtmp[i][j] = v[i][j];
                    }
                }
            }
        }
        else{
            for (k = 1; k <= Tmax; k++){
                i = istart;
                for (i = istart; i <= iend-1; i++){
                    for (j = 1; j < n-1; j++){

                        // Do usual computation with u_i,j = alpha * (u_i-1,j + u_i+1,j) + 
                        u[i][j] = alpha_u*(utmp[i-1][j] + utmp[i+1][j]) + beta_u*utmp[i][j] + gamma_u*(utmp[i][j-1] + utmp[i][j+1]) - u[i][j]*v[i][j]*v[i][j] + F*(1. - u[i][j]);
                        v[i][j] = alpha_v*(vtmp[i-1][j] + vtmp[i+1][j]) + beta_v*vtmp[i][j] + gamma_v*(vtmp[i][j-1] + vtmp[i][j+1]) + u[i][j]*v[i][j]*v[i][j] - (F+K)*v[i][j];
                    }

                    // left-right Periodic boundary conditions:
                    u[i][n-1] = alpha_u*(utmp[i-1][n-1] + utmp[i+1][n-1]) + beta_u*utmp[i][n-1] + gamma_u*(utmp[i][n-2] + utmp[i][0]) - u[i][n-1]*v[i][n-1]*v[i][n-1] + F*(1. - u[i][n-1]);
                    v[i][n-1] = alpha_v*(vtmp[i-1][n-1] + vtmp[i+1][n-1]) + beta_v*vtmp[i][n-1] + gamma_v*(vtmp[i][n-2] + vtmp[i][0]) + u[i][j]*v[i][n-1]*v[i][n-1] - (F+K)*v[i][n-1];
                }

                i = istart;
                for (i = istart; i <= iend; i++){
                    for (j = 0; j <= n; j++){
                        utmp[i][j] = u[i][j];
                        vtmp[i][j] = v[i][j];
                    }
                }
            }
        }
    }

    else {
        int count;
        for (k = 1; k <= Tmax; k++){
            count = iend-1;
            while (count >= istart){
                //printf("i = %d\n",i);
                for (j = 1; j < n-1; j++){

                    // Do usual computation with u_i,j = alpha * (u_i-1,j + u_i+1,j) + 
                    u[count][j] = alpha_u*(utmp[count-1][j] + utmp[count+1][j]) + beta_u*utmp[count][j] + gamma_u*(utmp[count][j-1] + utmp[count][j+1]) - u[count][j]*v[count][j]*v[count][j] + F*(1. - u[count][j]);
                    v[count][j] = alpha_v*(vtmp[count-1][j] + vtmp[count+1][j]) + beta_v*vtmp[count][j] + gamma_v*(vtmp[count][j-1] + vtmp[count][j+1]) + u[count][j]*v[count][j]*v[count][j] - (F+K)*v[count][j];
                }

                // left-right Periodic boundary conditions:
                u[count][n-1] = alpha_u*(utmp[count-1][n-1] + utmp[count+1][n-1]) + beta_u*utmp[count][n-1] + gamma_u*(utmp[count][n-2] + utmp[count][0]) - u[count][n-1]*v[count][n-1]*v[count][n-1] + F*(1. - u[count][n-1]);
                v[count][n-1] = alpha_v*(vtmp[count-1][n-1] + vtmp[count+1][n-1]) + beta_v*vtmp[count][n-1] + gamma_v*(vtmp[count][n-2] + vtmp[count][0]) + u[count][j]*v[count][n-1]*v[count][n-1] - (F+K)*v[count][n-1];

                count = count-1;    
            }

            i = istart;
            for (i = istart; i <= iend; i++){
                for (j = 0; j <= n; j++){
                    utmp[i][j] = u[i][j];
                    vtmp[i][j] = v[i][j];
                }
            }
        }
    }

    if (rank == 0){

        clock_gettime(CLOCK_MONOTONIC, &end);
        time_lapsed = (end.tv_sec - begin.tv_sec) + (double)(end.tv_nsec - begin.tv_nsec)/BILLION;
        printf("\nprint 'Time for algorithm to complete:',%f,'seconds.'\n",time_lapsed);

        fprintf(myA,"\n");
        fprintf(myA,"\ndef myAf():\n");
        fprintf(myA,"\treturn array([ ");

        for (i = 0; i <= m; i++){
            fprintf(myA,"[ ");
            for (j = 0; j <= n; j++){
                if (j != n){
                    fprintf(myA,"%f, ",utmp[i][j]);
                }
                else{
                    fprintf(myA,"%f ",utmp[i][j]);
                }
            }
            if (i != m){
                fprintf(myA,"],\n");
            }
            else{
                fprintf(myA,"]");
             }
        }

        fprintf(myA,"])\n");

        fprintf(myB,"\ndef myBf():\n");
        fprintf(myB,"\treturn array([");

        for (i = 0; i <= m; i++){
            fprintf(myB,"[ ");
            for (j = 0; j <= n; j++){
                if (j != n){
                    fprintf(myB,"%f, ",vtmp[i][j]);
                }
                else{
                    fprintf(myB,"%f ",vtmp[i][j]);
                }
            }
            if (i != m){
                fprintf(myB,"],\n");
            }
            else{
                fprintf(myB,"]");
             }
        }
        fprintf(myB,"])\n");


        fclose(myA);
        fclose(myB);

    }

    MPI_Finalize();

    return 0;
}

// For experimentation with different initial conditions

double f(double x, double y){
    return x - x*x + y - y*y; //sin(x*x + y*y);
//exp(20*(x-1./2)*(x-1./2) - 20*(y-1./2)*(y-1./2));//x - x*x + y - y*y;
}

double g(double x, double y){
    return sin(x*x + y*y); //sin(x*x + y*y);
//exp(20*(x-1./2)*(x-1./2) - 20*(y-1./2)*(y-1./2));//x - x*x + y - y*y;
}

อัลกอริธึมนี้เป็นวิธีการส่งต่อออยเลอร์บนโดเมน 2 มิติเป็นระยะ (อาร์เรย์ 2 มิติ) และเพื่อความชัดเจน ฉันจึงละส่วนต่างๆ ไว้มากมาย เว้นแต่ว่าจำเป็นต้องใช้มากกว่านี้ ผลลัพธ์เริ่มต้นและผลลัพธ์สุดท้ายจะถูกส่งออกไปยังไฟล์โดยโปรเซสเซอร์หลัก (อันดับ 0 ตามโค้ด) พร้อมที่จะลงจุด

แนวคิดที่ฉันมีอยู่ในใจคือการแบ่งโดเมนระหว่างโปรเซสเซอร์ออกเป็นขนาด (# แถว)/(# ของโปรเซสเซอร์) โดยที่ครึ่งแรกของโปรเซสเซอร์ทั้งหมดทำครึ่งบนของโดเมน (เริ่มต้นที่กึ่งกลางถึง สูงสุด). จากนั้น อีกครึ่งหนึ่งของโปรเซสเซอร์จะทำหน้าที่ครึ่งล่างของโดเมน (เริ่มจากตรงกลางไปด้านล่าง)

อย่างไรก็ตาม มีการอัปเดตเพียงครึ่งล่างของโดเมนเท่านั้น ซึ่งทำให้ฉันเชื่อว่ามี 'สภาพการแข่งขัน' บางอย่างเกิดขึ้น

--แก้ไข--

มีการใช้รหัสเดิมแทน

ฉันคิดว่าฉันรู้ว่าปัญหาคืออะไร โปรเซสเซอร์แต่ละตัวมีสำเนาโดเมนที่กำลังอัปเดต ของตัวเอง 'ในเครื่อง' ดังนั้นเมื่ออันดับ 0 กำลังพิมพ์เป็นไฟล์ มันกำลังพิมพ์เป็นเวอร์ชัน 'ท้องถิ่น' ของโดเมน ซึ่งบนโปรเซสเซอร์สองตัว ฉันจะเห็นครึ่งหนึ่งของ 'รูปภาพทั้งหมด'

อย่างไรก็ตาม สิ่งที่ฉันต้องการคือให้โปรเซสเซอร์แต่ละตัวอัปเดตส่วนของโดเมน จากนั้นให้ตัวประมวลผล 0 พิมพ์โดเมนที่อัปเดตทั้งหมดไปยังไฟล์ ฉันจะทำสิ่งนี้ได้อย่างไรหากนี่คือปัญหา


person BudRoz    schedule 13.12.2015    source แหล่งที่มา
comment
ฉันไม่เชื่อว่าปัญหาของคุณเกี่ยวข้องกับ MPI หรือสภาพการแข่งขันจริงๆ ดูเหมือนว่าจะเป็นข้อบกพร่องง่ายๆ ในการจัดการลูปและดัชนี (หรือแม้แต่การสลับวงเล็บ for ลูป และเงื่อนไข if และ else ที่ไม่ถูกต้อง) ในขณะนี้ ตัวอย่างของคุณเปิดเผยสิ่งนั้นทุกประการ แต่อาจเป็นปัญหาเรื่องการคัดลอก / วาง / แก้ไข คุณช่วยกรุณาโพสต์รหัสที่แน่นอนแทนได้ไหม?   -  person Gilles    schedule 13.12.2015
comment
คำแนะนำในการเพิ่มประสิทธิภาพโดยเปล่าประโยชน์: ในปัจจุบัน ทุกอันดับกำลังดำเนินการวนซ้ำที่เติม u, v, utmp และ vtmp ซึ่งทำให้การใช้ MPI_Bcast ซ้ำซ้อน คุณสามารถทำได้ในอันดับ 0 เท่านั้น จากนั้นออกอากาศอาร์เรย์ทั้งหมดโดยให้ตัวชี้ไปยังองค์ประกอบ [0][0] และจำนวน (n+1)*(m+1) หรือคุณสามารถกำจัดการออกอากาศทั้งหมดและปล่อยให้แต่ละกระบวนการเติมอาร์เรย์ด้วยตัวเอง   -  person Hristo Iliev    schedule 13.12.2015
comment
@Gilles มันจะยาวกว่านี้ แต่ฉันคิดว่าสามารถเพิกเฉยได้หากจำเป็น   -  person BudRoz    schedule 13.12.2015
comment
@HristoIliev ฉันคิดว่าฉันสามารถละทิ้งการออกอากาศได้ แต่ฉันไม่แน่ใจ ฉันจะจำไว้เสมอ   -  person BudRoz    schedule 13.12.2015


คำตอบ (1)


ตกลง ในที่สุดฉันก็มีโอกาสอ่านโค้ด และใช่ คุณถูกต้องในการวิเคราะห์ของคุณ เนื่องจากกระบวนการ #0 มีการอัปเดตส่วนแบ่งโดเมนของตัวเองเท่านั้น สิ่งที่พิมพ์จะเกี่ยวข้องกับส่วนนี้เท่านั้น ไม่ใช่สำหรับ ทั้งโดเมน ดังนั้น คุณมีสองตัวเลือกสำหรับโค้ดของคุณ:

  1. เพื่อรักษาโครงสร้างปัจจุบันและมีกระบวนการ #0 เพื่อรวบรวมข้อมูลทั้งหมดจากกระบวนการอื่นก่อนที่จะพิมพ์ผลลัพธ์ลงในไฟล์ หรือ
  2. เลือกใช้แนวทางแบบขนานโดยสมบูรณ์และให้กระบวนการทั้งหมดสร้างข้อมูลของตนเอง ทำการคำนวณ และสุดท้ายก็พิมพ์ส่วนแบ่งของตนเองในแบบคู่ขนาน

ไม่จำเป็นต้องพูดว่าแนวทางที่สองดีกว่าและมีประสิทธิภาพมากกว่ามากเช่นกัน ยิ่งไปกว่านั้น มันทำลายแนวทางมาสเตอร์ทาสที่ไร้ประโยชน์ที่คุณมีอยู่ในขณะนี้ (ขออภัยที่ฉันอดไม่ได้ที่จะพูดถึงเรื่องนั้น) .

สมมติว่าคุณจะใช้แนวทางหมายเลข 2 มันจะแปลว่าอะไร ดี,

  1. คุณจะคำนวณขีดจำกัดดัชนีของคุณเหมือนกับที่คุณทำจนถึงตอนนี้ และจัดสรร เฉพาะส่วนแบ่งของอาร์เรย์ประมวลผลที่กระบวนการปัจจุบันรับผิดชอบ บวกกับเลเยอร์พิเศษที่ล้อมรอบมัน เรียกว่าเลเยอร์โกสต์ . ซึ่งหมายความว่า หากคุณต้องการโดเมนที่ใหญ่ขึ้น โดยการเพิ่มจำนวนโหนดประมวลผล คุณจะเพิ่มปริมาณข้อมูลโดยรวมที่คุณจะสามารถจัดการได้ด้วย รหัสสามารถปรับขนาดได้ในเรื่องนั้น และเนื่องจากอัลกอริทึมของโค้ดของคุณดูน่าสงสัยเหมือนกับสเตนซิล 5 จุด เลเยอร์โกสต์ของคุณจึงมีความกว้าง 1 เซลล์ ซึ่งจะไม่แสดงถึงการถ่ายโอนข้อมูลมากนัก
  2. คุณจะต้องเริ่มต้นข้อมูลของคุณและเริ่มคำนวณ พูดง่ายๆ หลังจากการวนซ้ำ k แต่ละครั้ง คุณจะต้องแลกเปลี่ยนข้อมูลระหว่างกระบวนการต่างๆ สำหรับเลเยอร์โกสต์ เพื่อเผยแพร่สิ่งที่มาจากโดเมนที่อยู่ติดกัน โปรดทราบว่านี่เป็นปัญหาที่คุณมีอยู่แล้วในโค้ดปัจจุบันของคุณ (เนื่องจากคุณข้ามขั้นตอนบังคับนี้) ซึ่งทำให้ผิดโดยไม่คำนึงถึงปัญหาการพิมพ์ขั้นสุดท้าย
  3. ในที่สุดกระบวนการทั้งหมดจะเขียนการแบ่งปันโดเมนของตนเองแบบขนานโดยใช้ MPI-IO ซึ่งทำได้โดยการสร้าง "มุมมอง" ต่อกระบวนการของไฟล์เอาต์พุต โดยที่ข้อมูลจะเหมาะสมสำหรับการประกอบผลลัพธ์โดยรวม

โดยรวมแล้ว นี่เป็นงานเล็กน้อย (มากกว่าที่ฉันสามารถจัดสรรเพื่อตอบคำถาม SO ได้) อย่างไรก็ตาม แม้ว่าคุณจะตัดสินใจว่าจะไม่ใช้ตัวเลือกนี้ การแก้ไขโค้ดของคุณ (โดยเฉพาะอย่างยิ่งการจัดการการแลกเปลี่ยนข้อมูลในแต่ละขั้นตอน) จะใช้เวลานานเกือบเท่าๆ กัน ดังนั้นผมขอแนะนำให้คุณ "คิดแบบคู่ขนาน" และทำให้มันถูกต้องจากทุกมุมมอง

อีกทางหนึ่ง หากคุณไม่ต้องการใช้เวลานานในการขนาน MPI เต็มรูปแบบ และสมมติว่าการใช้หน่วยความจำไม่เป็นปัญหาสำหรับคุณ คุณสามารถลองใช้การขนาน OpenMP ซึ่งควรจะตรงไปตรงมา โดยเริ่มจากโค้ดเวอร์ชันตามลำดับ อย่างไรก็ตาม เนื่องจากโค้ดของคุณมีแนวโน้มที่จะผูกกับหน่วยความจำ อย่าคาดหวังว่าจะได้รับประโยชน์มากเกินไปจากการทำงานคู่ขนานของ OpenMP

person Gilles    schedule 14.12.2015