[关闭]
@codejan 2017-12-08T01:57:55.000000Z 字数 3998 阅读 807

并行计算

计算机


程序计时方法
另外, time .\a.out 可以精确计算a.out的运行时间

OpenMP

hello world: 感受并行

#pragma omp parallel
在下面的花括号(必须换行)中写入用于并行的代码, 需要注意:
- 各个线程执行顺序随机, 执行速度不完全相等
- 利用 omp_get_thread_num() 可以得到每个进程的编号, 然后根据编号可以对不同的进程进行不同的操作

  1. #include <omp.h>
  2. #include <stdio.h>
  3. int main(){
  4. #pragma omp parallel
  5. {
  6. int ID = omp_get_thread_num();
  7. printf("hello(%d) ", ID);
  8. // int tmp;
  9. // for(int i = 1; i <= 100000; i++) tmp += i*i;
  10. printf("world(%d)\n", ID);
  11. }
  12. }

计算pi: 添加临界区

#pragma omp critial 用来指定并行代码中的临界区, 每次只能有一个线程对临界区执行操作.
比如下面计算pi的代码中, 如果不对area += 4/(1 + x*x);添加临界区, 当同时有两个线程加area时, 很容易丢掉一个

  1. //tjh 2017.12.6
  2. //calculate Pi by numerical integration
  3. //use #pragma omp critical to avoid wrong answer when parallel
  4. #include <omp.h>
  5. #include <stdio.h>
  6. int main(){
  7. double area, pi, x;
  8. int i, n;
  9. area = 0;
  10. n = 1000000;
  11. #pragma omp parallel for
  12. for(i = 0; i < n; i++){
  13. x = (i+0.5) / n;
  14. #pragma omp critical
  15. area += 4/(1 + x*x);
  16. }
  17. pi = area / n;
  18. printf("%.10f", pi);
  19. }

素数筛: 分块计算, 提高效率

  1. #include <stdio.h>
  2. #include <time.h>
  3. #define N 50000001
  4. int prime[N/10], isnot_prime[N];
  5. int main(){
  6. clock_t start, end;
  7. start = clock();
  8. int cnt = 0;
  9. for(int i = 2; i < N; i++){
  10. if(isnot_prime[i] == 0){
  11. prime[cnt++] = i;
  12. for(int j = i+i; j < N; j += i){
  13. isnot_prime[j] = 1;
  14. }
  15. }
  16. }
  17. end = clock();
  18. printf("%d, time = %f\n", cnt, (double)(end-start)/1000000);
  19. return 0;
  20. }
  1. //tjh 2017.12.3
  2. //find prime : NlogN
  3. //OpenMP version
  4. #include <stdio.h>
  5. #include <omp.h>
  6. #define N 50000001
  7. int prime[N/10], isnot_prime[N];
  8. int main(){
  9. int cnt = 0;
  10. // #pragma omp parallel for //wrong: 前后关系
  11. for(int i = 2; i*i < N; i++){
  12. if(isnot_prime[i] == 0){
  13. prime[cnt++] = i;
  14. #pragma omp parallel for
  15. for(int j = i+i; j < N; j+=i){
  16. isnot_prime[j] = 1;
  17. }
  18. isnot_prime[i] = 0;
  19. }
  20. }
  21. cnt = 0;
  22. for(int i = 2; i < N; i++){
  23. if(isnot_prime[i] == 0) cnt++;
  24. }
  25. return 0;
  26. }

矩阵乘法

  1. //2017.12.6
  2. //matrix multiplicaiton
  3. #include <omp.h>
  4. #include <stdio.h>
  5. int a[5005][5005], b[5005][5005], c[5005][5005];
  6. int main(){
  7. freopen("data.txt", "r", stdin);
  8. int n;
  9. scanf("%d", &n);
  10. //read files + openmp : very slow
  11. for(int i = 0; i < n; i++){
  12. for(int j = 0; j < n; j++){
  13. scanf("%d", &a[i][j]);
  14. }
  15. }
  16. for(int i = 0; i < n; i++){
  17. for(int j = 0; j < n; j++){
  18. scanf("%d", &b[i][j]);
  19. c[i][j] = 0;
  20. }
  21. }
  22. #pragma omp parallel for //only parallel for i, 因此不需要临界区
  23. for(int i = 0; i < n; i++){
  24. for(int j = 0; j < n; j++){
  25. for(int k = 0; k < n; k++){
  26. c[i][j] += a[i][k] * b[k][j];
  27. }
  28. }
  29. }
  30. int ans = 0;
  31. for(int i = 0; i < n; i++) ans += c[i][i];
  32. printf("%d", ans);
  33. }

MPI

编译mpicc name.c -o name
运行mpirun -np x name -np标记要生成进程个数

电路可满足性计算

  1. //tjh 2017.12.6
  2. //mpi: check circuit
  3. #include <mpi.h>
  4. #include <stdio.h>
  5. int check_circuit(int id, int z){
  6. int v[16];
  7. int i;
  8. for(i = 0; i < 16; i++){
  9. if( z&(1<<i) ) v[i] = 1;
  10. else v[i] = 0; //remember to initialize
  11. }
  12. // for(i = 0; i < 16; i++) printf("%d", v[i]);
  13. // printf("\n");
  14. if( (v[0] || v[1]) && (!v[1] || !v[3]) && (v[2] || v[3])
  15. && (!v[3] || !v[4]) && (v[4] || !v[5]) && (v[5] || !v[6])
  16. && (v[5] || v[6]) && (v[6] || !v[15]) && (v[7] || !v[8])
  17. && (!v[7] || !v[13]) && (v[8] || v[9])
  18. && (v[8] || !v[9]) && (!v[9] || !v[10])
  19. && (v[9] || v[11]) && (v[10] || v[11])
  20. && (v[12] || v[13]) && (v[13] || !v[14])
  21. && (v[14] || v[15]) ){
  22. printf("%d)", id);
  23. for(i = 0; i < 16; i++) printf("%d", v[i]);
  24. printf("\n");
  25. return 1;
  26. }
  27. return 0;
  28. }
  29. int main(int argc, char *argv[]){
  30. int k, id, p;
  31. int global_ans = 0;
  32. int ans = 0;
  33. MPI_Init(&argc, &argv);
  34. MPI_Comm_rank(MPI_COMM_WORLD, &id);
  35. MPI_Comm_size(MPI_COMM_WORLD, &p);
  36. ans = 0;
  37. for(k = id; k < 65536; k += p) ans += check_circuit(id, k);
  38. MPI_Reduce(&ans, &global_ans, 1, MPI_INT, MPI_SUM, 0, MPI_COMM_WORLD);
  39. if(id==0) printf("There are %d different solutions.", global_ans);
  40. printf("Process %d is done\n", id);
  41. fflush(stdout);
  42. MPI_Finalize();
  43. return 0;
  44. }

CUDA

向量求和(普通)

  1. #include <iostream>
  2. #include <math.h>
  3. void add(int n, float *x, float *y){
  4. for(int i = 0; i < n; i++)
  5. y[i] = x[i] + y[i];
  6. }
  7. int main(void){
  8. int N = 1 << 20;
  9. float *x = new float[N];
  10. float *y = new float[N];
  11. for(int i = 0; i < N; i++){
  12. x[i] = 1.0f;
  13. y[i] = 2.0f;
  14. }
  15. add(N, x, y);
  16. delete [] x;
  17. delete [] y;
  18. return 0;
  19. }

向量求和(cuda)

  1. #include <iostream>
  2. #include <math.h>
  3. __global__
  4. void add(int n, float *x, float *y){
  5. for(int i = 0; i < n; i++)
  6. y[i] = x[i] + y[i];
  7. }
  8. int main(void){
  9. int N = 1 << 20;
  10. float *x, float *y;
  11. cudaMallocManaged(&x, N*sizeof(float));
  12. cudaMallocManaged(&y, N*sizeof(float));
  13. for(int i = 0; i < N; i++){
  14. x[i] = 1.0f;
  15. y[i] = 2.0f;
  16. }
  17. add<<<1,1>>>(N, x, y);
  18. cudaDeviceSynchronize();
  19. cudaFree(x);
  20. cudaFree(y);
  21. return 0;
  22. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注