首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >openMP输出的可重现性问题

openMP输出的可重现性问题
EN

Stack Overflow用户
提问于 2019-04-09 07:59:13
回答 2查看 201关注 0票数 1

我正在学习openMP教程,并且随着我的进步,我编写了一个代码的openMP版本,它使用一个积分来计算PI。

我已经写了一个连续的版本,所以我知道串行版本是可以的。一旦openMP版本完成,我注意到每次运行它,它都会给我一个不同的答案。如果我运行几次,我可以看到输出大致在正确的数字附近,但我仍然没有预料到几个openMP运行给出了不同的答案。

代码语言:javascript
运行
AI代码解释
复制
#include<stdio.h>
#include<stdlib.h>
#include<omp.h>

void main()

{ int nb=200,i,blob;



 float summ=0,dx,argg;
 dx=1./nb;

 printf("\n dx------------: %f \n",dx);


 omp_set_num_threads(nb);
 #pragma omp parallel
 {

 blob=omp_get_num_threads();

 printf("\n we have now %d number of threads...\n",blob);

 int ID=omp_get_thread_num();
 i=ID;
 printf("\n i is now: %d \n",i);

 argg=(4./(1.+i*dx*i*dx))*dx;
 summ=summ+argg;
 printf("\t\t and summ is %f \n",summ);
 }


 printf("\ntotal summ after loop: %f\n",summ);

 }

我在RedHat上使用gcc -f mycode.c -fopenmp编译了这段代码,当我运行它时,比如说3次,我得到:

3.117

3.113

3.051

有人能帮我理解我为什么得到不同的结果吗?我做错了什么吗?并行只是分裂积分间隔,但是当矩形被计算出来时,当它们在结尾被求和时,应该是一样的,不是吗?

系列版本给了我3.13

(我没有得到3.14是正常的,因为我使用了一个非常粗糙的积分抽样,在0到1之间只有200个除法)

我也试图增加一个障碍,但我仍然得到不同的答案,虽然更接近串行版本,仍然有一个利差值和不相同的.

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2019-04-09 09:33:35

我认为问题在于在并行循环之外声明int ifloat argg

正在发生的情况是,所有200个线程都覆盖iargg,因此有时线程的argg会被来自另一个线程的argg覆盖,从而导致您观察到的不可预知的错误。

下面是一个工作代码,它总是打印相同的值(最多6个小数):

代码语言:javascript
运行
AI代码解释
复制
void main()
{
    int nb = 200, blob;
    float summ = 0, dx;// , argg;
    dx = 1. / nb;

    printf("\n dx------------: %f \n", dx);

    omp_set_num_threads(nb);
#pragma omp parallel
    {

        blob = omp_get_num_threads();

        printf("\n we have now %d number of threads...\n", blob);

        int i = omp_get_thread_num();
        printf("\n i is now: %d \n", i);

        float argg = (4. / (1. + i * dx*i*dx))*dx;
        summ = summ + argg;
        printf("\t\t and summ is %f \n", summ);
    }

    printf("\ntotal summ after loop: %f\n", summ);
}

但是,将最后一行更改为%.9f显示,它实际上不是完全相同的浮点数。这是由于浮点加法的数值误差造成的。a+b+c不能保证结果与a+c+b相同。可以在下面的示例中尝试这样做:

首先,在定义了并行循环( float* arr = new float[nb]; )之后,在(并行循环)和arr[i] = argg; (并行循环)之前添加arr[i] = argg;(并行循环)。然后在并行循环的之后添加以下:

代码语言:javascript
运行
AI代码解释
复制
float testSum = 0;
for (int i = 0; i < nb; i++)
    testSum += arr[i];
printf("random sum: %.9f\n", testSum);

std::sort(arr, arr + nb);
testSum = 0;

for (int i = 0; i < nb; i++)
    testSum += arr[i];
printf("sorted sum: %.9f\n", testSum);

testSum = 0;
for (int i = nb-1; i >= 0; i--)
    testSum += arr[i];
printf("reversed sum: %.9f\n", testSum);

很可能,排序和反向和略有不同,尽管它们是由完全相同的200个数字相加而成的。

您可能需要注意的另一件事是,您很难找到一个能够并行运行200个线程的处理器。大多数通用处理器可以处理4到32个线程,而专用服务器处理器可以使用$15k Xeon白金9282来处理112个线程。

因此,我们通常做以下工作:

我们删除omp_set_num_threads(nb);以使用推荐的线程数

我们从for循环中删除int i = omp_get_thread_num();以使用int i

我们将循环重写为for循环:

代码语言:javascript
运行
AI代码解释
复制
#pragma omp parallel for
for (int i = 0; i < nb; i++)
    {...}

结果应该是相同的,但是现在只使用实际硬件上可用的线程。这样可以减少线程间的上下文切换,并提高代码的时间性能。

票数 2
EN

Stack Overflow用户

发布于 2019-04-09 09:46:33

问题来自变量summarggi。它们属于全局顺序范围,如果不采取预防措施,就不能修改。您将在线程之间进行竞争,这可能会导致这些var中出现一个意外的值。种族是完全不确定的,这就解释了你得到的不同结果。您还可以获得正确的结果或任何不正确的结果,这取决于读取和写入这些vars的时间。

处理这个问题的正确方法是:

  • 对于变量arggi:它们在全局范围内声明,但它们用于在线程中执行临时计算。您应该:要么在并行域中声明它们,使它们成为线程私有,要么在omp指令中添加private(argg,i)。注意,blob也有一个潜在的问题,但是它的值在所有线程中是相同的,这不应该修改程序的行为。
  • 对于变量summ,情况则不同。这实际上是一个全局变量,它从线程中积累一些值。它必须保持全局,但在修改它时必须添加atomic openmp指令。对变量的完整读-修改-写操作将变得不可打破,这将确保无竞争修改。

下面是您的代码的修改版本,它提供了一致的结果(但是浮点数不是关联的,最后一个小数点可能会改变)。

代码语言:javascript
运行
AI代码解释
复制
#include<stdio.h>
#include<stdlib.h>
#include<omp.h>

void main()

{
  int nb=200,i,blob;
  float summ=0,dx,argg;
  dx=1./nb;

  printf("\n dx------------: %f \n",dx);

  omp_set_num_threads(nb);
# pragma omp parallel private(argg,i)
  {
    blob=omp_get_num_threads();

    printf("\n we have now %d number of threads...\n",blob);

    int ID=omp_get_thread_num();
    i=ID;
    printf("\n i is now: %d \n",i);

    argg=(4./(1.+i*dx*i*dx))*dx;
    #pragma omp atomic
    summ=summ+argg;

    printf("\t\t and summ is %f \n",summ);
  }

  printf("\ntotal summ after loop: %f\n",summ);

}

如前所述,这不是使用线程的最佳方式。创建和同步线程是昂贵的,很少需要有更多的线程数量的核心。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/55596868

复制
相关文章
Matlab绘制包含双Y轴的图
创建左右两侧都有 y 轴的坐标区。yyaxis left 命令用于创建坐标区并激活左侧。后续图形函数(例如 plot)的目标为活动侧。绘制数据对左侧 y 轴的图。
用户9925864
2022/07/27
2.1K0
Matlab绘制包含双Y轴的图
OriginLab绘制分组双Y轴图形
请注意,本文编写于 938 天前,最后修改于 123 天前,其中某些信息可能已经过时。
曼亚灿
2023/05/17
1.1K0
OriginLab绘制分组双Y轴图形
origin如何绘制双y轴柱状图_Graphpad柱状图双Y轴
tips:origin横坐标的标注如何修改成双行显示呢? shift+enter,可以换行
全栈程序员站长
2022/11/11
3.3K0
origin如何绘制双y轴柱状图_Graphpad柱状图双Y轴
matlab绘制figure的x y轴特殊标签数据
做数据分析的Matlab用户最常见的问题之一是如何在日期轴上绘制数据。很多时候,分析师最初会使用Excel处理数据,然后用相应的工具去处理数据,分析数据。Excel有一种在日期轴上绘制数据的简单方法,但在Matlab中使用日期轴需要麻烦一点。但matlab针对这种特殊情况也有对应的一些函数,使用Matlab完成这项任务并不难,而且和大多数Matlab函数一样,它具有相当大的通用性。
用户9925864
2022/12/16
3K0
matlab绘制figure的x y轴特殊标签数据
【R语言】如何绘制截断Y轴的柱形图
在绘制柱形图的时候, 我们经常会遇到Y轴部分数据范围很广的情况。有些数值很大,但是有些有非常小,不在一个尺度范围内。如果直接使用最大值作为y轴的范围,那么那些数值很小的柱子就会显得很矮,画出来的图会很难看。遇到这种情况我们该如何处理呢?今天就给大家分享一下截断Y轴的柱形图。
生信交流平台
2022/09/21
2.3K0
【R语言】如何绘制截断Y轴的柱形图
如何在WPF绘图中(通过贝塞尔曲线)绘制平滑曲线
GDI图形系统已经形成了很多年。它提供了2D图形和文本功能,以及受限的图像处理功能,在传统的Windows Form 编程中,我们经常使用Graphics图形对象的DrawCurve方法绘制平滑的曲线。
程序你好
2020/11/19
3.1K0
如何在WPF绘图中(通过贝塞尔曲线)绘制平滑曲线
Python-R-双Y轴可视化绘制
最近有很多小伙伴私信我关于双Y轴图的绘制方法? 这里我就直接给出Python-matplotlib绘制方法和R-ggplot2的绘制方法,主要的知识点如下:
DataCharm
2021/02/22
8910
Python-R-双Y轴可视化绘制
如何用R绘制双y轴柱状图
绘制上面这个漂亮的图,要注释以下3点: 1. 双y轴 2. 颜色渐变 3. 横坐标的label对齐 代码及解释如下: library(RColorBrewer) # 载入颜色包 par(mar=c(5
生信交流平台
2020/08/05
2.6K0
如何用R绘制双y轴柱状图
Python-matplotlib双Y轴可视化绘制
最近有很多小伙伴私信我关于双Y轴图的绘制方法? 这里我就直接给出Python-matplotlib绘制方法和R-ggplot2的绘制方法,主要的知识点如下:
bugsuse
2021/01/04
2.1K0
Python-matplotlib双Y轴可视化绘制
python双Y轴
import matplotlib.pyplot as plt import numpy as np x = np.arange(0., np.e, 0.01) y1 = np.exp(-x) y2 = np.log(x) fig = plt.figure() sns.set_style('white') ax1 = fig.add_subplot(111) ax1.plot(x, y1) ax1.set_ylabel('Y values for exp(-x)') ax1.set_title("Dou
用户1359560
2018/08/27
1.3K0
python双Y轴
echart 双折线 双Y轴, 折线,柱形 双Y轴图
双折线图 双Y轴 双坐标系坐标 option = { xAxis: { type: 'category', data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'] }, yAxis: [ {name: '数值',type: 'value', interval: 300, position:'left'}, {type: 'value', pos
拿我格子衫来
2022/01/24
1.9K0
echart 双折线 双Y轴, 折线,柱形 双Y轴图
echarts的双y轴显示
第一步: 引入echarts import echarts from "echarts"; Vue.prototype.$echarts = echarts //引入组件(全局引入) 第二步: id绑定 <div id="pie"> /// pie 用于存放所要绘制的图形 第三步: 配置options,创建echarts实例 option1: { title: { text: "双坐标轴事例", //标题 show: f
用户4344670
2019/08/28
4.9K0
echarts实现多个y轴
在日常画图,如柱形图、折线图这些图表,需要两组或者两组以上不同的数据,且数据的大小有一定的差异时,通常是需要用两个y轴来体现的。
算法与编程之美
2022/02/17
1.9K0
如何绘制一个figure中有一个x轴,三个y轴?
1、点击[命令行窗口] 2、按<Enter>键 3、点击[命令行窗口] 4、按<Enter>键
裴来凡
2022/05/28
1.2K0
如何绘制一个figure中有一个x轴,三个y轴?
Echarts多Y轴探索
ECharts,一个纯 Javascript 的图表库,可以流畅的运行在 PC 和移动设备上,兼容当前绝大部分浏览器(IE8/9/10/11,Chrome,Firefox,Safari等),底层依赖轻量级的 Canvas 类库 ZRender,提供直观,生动,可交互,可高度个性化定制的数据可视化图表。
孟君
2019/09/24
4.9K0
Echarts多Y轴探索
【好久不见】细评python绘制双y轴图的几种方法
双y轴图在实际科研过程中比较常见。但我们常常会为了要把某个图形置于顶层,又或者是要把某个图形对应的y轴固定在某一侧而感到烦恼。别怕,今天这篇推文将会解决你的疑虑!
自学气象人
2022/10/09
3.2K0
【好久不见】细评python绘制双y轴图的几种方法
Echarts设置y轴值间隔
需求:如图,y轴之间的距离太小,这样就太过于拥挤了,现在要修改echarts里面的属性,设置y轴值间隔让图表看上去舒服一些。
王小婷
2019/03/22
9.2K0
Echarts设置y轴值间隔
Stata | 调整 Y 轴文字顺序
鸽了一个暑假,最近试着渐渐更新起来。今天分享一个被好多强迫症小伙伴问到的问题:用 Stata 画图怎么更改 Y 轴文本的顺序。如下图所示,默认绘图的文字为每个字从左到右,但是一般论文在 Y 轴顶端的由上至下的排列。
PyStaData
2021/09/14
3.4K0
Stata | 调整 Y 轴文字顺序
点击加载更多

相似问题

将多个工作表中的ActiveX按钮合并为一个按钮

20

将两个或多个提交按钮合并为一个

242

如何将播放和暂停按钮合并为一个按钮

40

将多个页面上的多个输入按钮合并为单个html页面上的单个按钮

20

将分组单选按钮方法合并为一个?

11
添加站长 进交流群

领取专属 10元无门槛券

AI混元助手 在线答疑

扫码加入开发者社群
关注 腾讯云开发者公众号

洞察 腾讯核心技术

剖析业界实践案例

扫码关注腾讯云开发者公众号
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文