- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
刚开始接触OPENMP,想用它来求解波动方程,串口代码在这里:
#include <time.h>
#include <stdio.h>
#include <omp.h>
#include <math.h>
#define GRID_SZ 3000
#define ARR_SZ GRID_SZ * GRID_SZ
#define PEAK_SZ 31
double *process_withoutomp() {
double start = omp_get_wtime();
int i, j;
double dt = 0.04, C = 16, K = 0.1, h = 6;
double *data, *olddata, *newdata, *tmp;
double x[PEAK_SZ][PEAK_SZ], linspace[PEAK_SZ], delta = 2.0/(PEAK_SZ-1.0);
data = (double*)malloc(sizeof(double)*ARR_SZ);
olddata = (double*)malloc(sizeof(double)*ARR_SZ);
newdata = (double*)malloc(sizeof(double)*ARR_SZ);
for(i = 0; i < ARR_SZ; i++){
data[i] = 1.0;
}
for(i = 0; i < PEAK_SZ; i++){
linspace[i] = -1.0 + delta * i;
}
for(i = 0; i < PEAK_SZ; i++){
for(j = 0; j < PEAK_SZ; j++){
x[i][j] = linspace[i];
}
}
for(i = 0; i < PEAK_SZ; i++){
for(j = 0; j < PEAK_SZ; j++){
data[(i+20)*GRID_SZ+j+20] += h * exp( -5 * (pow(x[i][j], 2 ) + pow(x[j][i], 2 )));
}
}
for(i = 0; i < ARR_SZ; i++){
olddata[i] = data[i];
}
for(i = 0; i < 20; i++){
sequential_update_withoutomp( data, olddata, newdata, C, K, dt);
tmp = olddata;
olddata = data;
data = newdata;
newdata = tmp;
}
double end = omp_get_wtime();
printf("without omp spend: %f\n",end-start);
return data;}void sequential_update_withoutomp(double *data, double *olddata, double *newdata, double C, double K, double dt ){
int i, j, add_i, sub_i, add_j, sub_j;
double pot;
for( i = 0; i < GRID_SZ; i++){
for( j = 0; j < GRID_SZ; j++){
add_i = i+1 >= GRID_SZ ? i : i+1;
add_j = j+1 >= GRID_SZ ? j : j+1;
sub_i = i-1 < 0 ? 0 : i-1;
sub_j = j-1 < 0 ? 0 : j-1;
pot = data[add_i*GRID_SZ+j]+
data[sub_i*GRID_SZ+j]+
data[add_j+i*GRID_SZ]+
data[sub_j+i*GRID_SZ]-
4*data[i*GRID_SZ+j];
newdata[i * GRID_SZ + j] =
( pow(C * dt, 2) * pot * 2 + 4 * data[i * GRID_SZ + j] - olddata[i * GRID_SZ + j] *(2 - K * dt) ) / (2 + K * dt);
}
}}
这里是使用的版本:
double *process_withomp() {
double start = omp_get_wtime();
int i, j;
double dt = 0.04, C = 16, K = 0.1, h = 6;
double *data, *olddata, *newdata, *tmp;
double x[PEAK_SZ][PEAK_SZ], linspace[PEAK_SZ], delta = 2.0/(PEAK_SZ-1.0);
data = (double*)malloc(sizeof(double)*ARR_SZ);
olddata = (double*)malloc(sizeof(double)*ARR_SZ);
newdata = (double*)malloc(sizeof(double)*ARR_SZ);
#pragma omp parallel for private(i) schedule(auto)
for(i = 0; i < ARR_SZ; i++){
data[i] = 1.0;
}
#pragma omp parallel for private(i,j) schedule(auto)
for(i = 0; i < PEAK_SZ; i++){
linspace[i] = -1.0 + delta * i;
for(j = 0; j < PEAK_SZ; j++) {
x[i][j] = linspace[i];
}
}
#pragma omp barrier
#pragma omp parallel for private(i,j) schedule(auto)
for(i = 0; i < PEAK_SZ; i++){
for(j = 0; j < PEAK_SZ; j++){
data[(i+20)*GRID_SZ+j+20] += h * exp( -5 * (pow(x[i][j], 2 ) + pow(x[j][i], 2 )));
}
}
#pragma omp barrier
#pragma omp parallel for private(i) schedule(auto)
for(i = 0; i < ARR_SZ; i++){
olddata[i] = data[i];
}
#pragma omp barrier
for(i = 0; i < 20; i++) {
sequential_update_withomp( data, olddata, newdata, C, K, dt);
tmp = olddata;
olddata = data;
data = newdata;
newdata = tmp;
}
double end = omp_get_wtime();
printf("with omp spend: %f\n",end-start);
return data;}void sequential_update_withomp(double *data, double *olddata, double *newdata, double C, double K, double dt ) {
int i, j;
double pot;
#pragma omp parallel for private(i,j,pot) schedule(auto)
for( i = 0; i < GRID_SZ; i++) {
for( j = 0; j < GRID_SZ; j++) {
pot = data[(i+1 >= GRID_SZ ? i : i+1)*GRID_SZ+j]+
data[(i-1 < 0 ? 0 : i-1)*GRID_SZ+j]+
data[(j+1 >= GRID_SZ ? j : j+1)+i*GRID_SZ]+
data[(j-1 < 0 ? 0 : j-1)+i*GRID_SZ]
-4*data[i*GRID_SZ+j];
newdata[i * GRID_SZ + j] =
(pow(C * dt, 2) * pot * 2 + 4 * data[i * GRID_SZ + j] - olddata[i * GRID_SZ + j]
* (2 - K * dt))
/ (2 + K * dt);
}
}}
这个版本运行良好,但是当我尝试使用任务替换它时,结果是正确的,但花费的时间更多:
double *process_withomp1() {
double start = omp_get_wtime();
int i, j;
double dt = 0.04, C = 16, K = 0.1, h = 6;
double *data, *olddata, *newdata, *tmp;
double x[PEAK_SZ][PEAK_SZ], linspace[PEAK_SZ], delta = 2.0/(PEAK_SZ-1.0);
data = (double*)malloc(sizeof(double)*ARR_SZ);
olddata = (double*)malloc(sizeof(double)*ARR_SZ);
newdata = (double*)malloc(sizeof(double)*ARR_SZ);
#pragma omp parallel for private(i) schedule(auto)
for(i = 0; i < ARR_SZ; i++){
data[i] = 1.0;
}
#pragma omp parallel for private(i,j) schedule(auto)
for(i = 0; i < PEAK_SZ; i++){
linspace[i] = -1.0 + delta * i;
for(j = 0; j < PEAK_SZ; j++) {
x[i][j] = linspace[i];
}
}
#pragma omp barrier
#pragma omp parallel for private(i,j) schedule(auto)
for(i = 0; i < PEAK_SZ; i++){
for(j = 0; j < PEAK_SZ; j++){
data[(i+20)*GRID_SZ+j+20] += h * exp( -5 * (pow(x[i][j], 2 ) + pow(x[j][i], 2 )));
}
}
#pragma omp barrier
#pragma omp parallel for private(i) schedule(auto)
for(i = 0; i < ARR_SZ; i++){
olddata[i] = data[i];
}
#pragma omp barrier
for(i = 0; i < 20; i++) {
sequential_update_withomp1( data, olddata, newdata, C, K, dt);
tmp = olddata;
olddata = data;
data = newdata;
newdata = tmp;
}
double end = omp_get_wtime();
printf("with omp spend: %f\n",end-start);
return data;}
void sequential_update_withomp1(double *data, double *olddata, double *newdata, double C, double K, double dt ) {
int i, j;
double pot;
#pragma omp parallel private(i,j,pot)
for( i = 0; i < GRID_SZ; i++) {
for( j = 0; j < GRID_SZ; j++) {
#pragma omp task
{
pot = data[(i+1 >= GRID_SZ ? i : i+1)*GRID_SZ+j]+
data[(i-1 < 0 ? 0 : i-1)*GRID_SZ+j]+
data[(j+1 >= GRID_SZ ? j : j+1)+i*GRID_SZ]+
data[(j-1 < 0 ? 0 : j-1)+i*GRID_SZ]
-4*data[i*GRID_SZ+j];
newdata[i * GRID_SZ + j] =
(pow(C * dt, 2) * pot * 2 + 4 * data[i * GRID_SZ + j] - olddata[i * GRID_SZ + j]
* (2 - K * dt))
/ (2 + K * dt);
}
}
}}
在我的 mac 上,serial 版本大约需要 7.7s,for 版本需要 3.7s,但是任务使用 53s。
有人知道这里出了什么问题吗?
提前致谢
最佳答案
这里有两点需要考虑:
在您的代码中,a) 太小,b) 已损坏。
一)在您的 task
示例中,内部循环的一次迭代 是一项任务,而在 parallel for
示例中,n 次迭代外循环是并行化的,即每个线程处理外循环的大量迭代。使用 schedule(static, 1)
,一个外部迭代将是每个线程的工作大小。请记住,所有并行都会增加开销,用于同步内容、簿记等。增加的成本必须通过并行执行的执行速度提高来补偿。找到合适的工作量是至关重要的,您希望尽可能多地保持一切忙碌,也许更多的工作量可以给调度程序一些空间来补偿任务/ block 之间的负载不平衡,但要尽可能少以保持较小的开销。
b)在您的并行区域中运行循环,意味着每个线程都在运行整个循环嵌套并多次创建所有任务。这就像并行运行串行程序多次。
void sequential_update_withomp1(double *data, double *olddata, double *newdata, double C, double K, double dt ) {
// ....
#pragma omp parallel private(i,j,pot)
{
// split loop among threads of parallel region
// i.e. create tasks in parallel
#pragma omp for
for( i = 0; i < GRID_SZ; i++) {
// coarse grained tasks (as in parallel for version)
#pragma omp task
{
// each inner for loop is one task
for( j = 0; j < GRID_SZ; j++) {
// ...
}
} // task
} // parallel for
} // parallel region
这给了我(2 个核心 x 2 个超线程):
serial: 4.839213
parallel for: 2.529813
task: 2.817615
注意:在这里实际使用任务没有意义,因为它们只会在并行 for 循环之上增加开销。
关于c - 为什么 OMP 任务运行速度比 OMP 慢?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48129831/
Task.WaitAll 方法等待所有任务,Task.WaitAny 方法等待一个任务。如何等待任意N个任务? 用例:下载搜索结果页面,每个结果都需要一个单独的任务来下载和处理。如果我使用 WaitA
我正在查看一些像这样的遗留 C# 代码: await Task.Run(() => { _logger.LogException(LogLevel.Error, mes
如何在 Linux 中运行 cron 任务? 关注此Q&A ,我有这个 cron 任务要运行 - 只是将一些信息写入 txt 文件, // /var/www/cron.php $myfile = fo
原谅我的新手问题,但我想按顺序执行三个任务并在剧本中使用两个角色: 任务 角色 任务 角色 任务 这是我到目前为止(任务,角色,任务): --- - name: Task Role Task ho
我有一个依赖于 installDist 的自定义任务 - 不仅用于执行,还依赖于 installDist 输出: project.task('run', type: JavaExec, depends
从使用 Wix 创建的 MSI 运行卸载时,我需要在尝试删除任何文件之前强行终止在后台运行的进程。主要应用程序由一个托盘图标组成,它反射(reflect)了 bg 进程监控本地 Windows 服务的
我想编写 Ant 任务来自动执行启动服务器的任务,然后使用我的应用程序的 URL 打开 Internet Explorer。 显然我必须执行 startServer先任务,然后 startApplic
使用 ASP.NET 4.5,我正在尝试使用新的 async/await 玩具。我有一个 IDataReader 实现类,它包装了一个特定于供应商的阅读器(如 SqlDatareader)。我有一个简
使用命令 gradle tasks可以得到一份所有可用任务的报告。有什么方法可以向此命令添加参数并按任务组过滤任务。 我想发出类似 gradle tasks group:Demo 的命令筛选所有任务并
除了sshexec,还有什么办法吗?任务要做到这一点?我知道您可以使用 scp 复制文件任务。但是,我需要执行其他操作,例如检查是否存在某些文件夹,然后将其删除。我想使用类似 condition 的东
假设我有字符串 - "D:\ApEx_Schema\Functions\new.sql@@\main\ONEVIEW_Integration\3" 我需要将以下内容提取到 diff 变量中 - 文档名
我需要编写一个 ant 任务来确定某个文件是否是只读的,如果是,则失败。我想避免使用自定义选择器来为我们的构建系统的性质做这件事。任何人都有任何想法如何去做?我正在使用 ant 1.8 + ant-c
这是一个相当普遍的计算机科学问题,并不特定于任何操作系统或框架。 因此,我对与在线程池上切换任务相关的开销感到有些困惑。在许多情况下,给每个作业分配自己的特定线程是没有意义的(我们不想创建太多硬件线程
我正在使用以下 Ansible playbook 一次性关闭远程 Ubuntu 主机列表: - hosts: my_hosts become: yes remote_user: my_user
如何更改 Ant 中的当前工作目录? Ant documentation没有 任务,在我看来,最好的做法是不要更改当前工作目录。 但让我们假设我们仍然想这样做——你会如何做到这一点?谢谢! 最佳答案
是否可以运行 cronjob每三天一次?或者也许每月 10 次。 最佳答案 每三天运行一次 - 或更短时间在月底运行一次。 (如果上个月有 31 天,它将连续运行 2 天。) 0 0 */3 * *
如何在 Gradle 任务中执行托管在存储库中的工具? 在我的具体情况下,我正在使用 Gradle 构建一个 Android 应用程序。我添加了一项任务,将一些 protobuf 数据从文本编码为二进
我的项目有下一个结构: Root |- A |- C (depends on A) \- B (depends on A) 对于所有子项目,我们使用自己的插件生成资源:https://githu
我设置了一个具有4个节点的Hadoop群集,其中一个充当HDFS的NameNode以及Yarn主节点。该节点也是最强大的。 现在,我分发了2个文本文件,一个在node01(名称节点)上,一个在node
在 TFS 2010 中为多个用户存储任务的最佳方式是什么?我只能为一项任务分配一个。 (例如:当我计划向所有开发人员演示时) (这是一个 Scrum Msf 敏捷项目,其中任务是用户故事的一部分)
我是一名优秀的程序员,十分优秀!