- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我得到了一些使用 OpenMP 进行并行化的代码,在各种函数调用中,我注意到这个 for
循环在计算时间上有一些好处。
double U[n][n];
double L[n][n];
double Aprime[n][n];
for(i=0; i<n; i++) {
for(j=0; j<n; j++) {
if (j <= i) {
double s;
s=0;
for(k=0; k<j; k++) {
s += L[j][k] * U[k][i];
}
U[j][i] = Aprime[j][i] - s;
} else if (j >= i) {
double s;
s=0;
for(k=0; k<i; k++) {
s += L[j][k] * U[k][i];
}
L[j][i] = (Aprime[j][i] - s) / U[i][i];
}
}
然而,在尝试将其并行化并在各处应用一些信号量之后(没有运气),我开始意识到 else if
条件对早期的 有很强的依赖性if
(L[j][i]
是一个用U[i][i]
处理过的数字,可以在早期的 if
),在我看来,由于竞争条件,它是不可并行化的。
是否可以并行化此代码,使 else if
仅在较早的 if
已经完成时执行?
最佳答案
在尝试并行化之前,先尝试简化。
例如,if
可以完全消除。
此外,代码访问矩阵的方式会导致最差 缓存性能。这可能是真正的瓶颈。
注意:在下面的更新 #3 中,我做了基准测试和缓存友好版本 fix5
,从更新 #2 开始,性能比原来的高出 3.9 倍。
我已经分阶段进行了清理,因此您可以看到代码转换。
有了这个,应该可以添加 omp
指令成功。正如我在顶部评论中提到的,变量的全局范围与函数范围会影响可能需要的更新类型(例如 omp atomic update
等)
作为引用,这是您的原始代码:
double U[n][n];
double L[n][n];
double Aprime[n][n];
for (i = 0; i < n; i++) {
for (j = 0; j < n; j++) {
if (j <= i) {
double s;
s = 0;
for (k = 0; k < j; k++) {
s += L[j][k] * U[k][i];
}
U[j][i] = Aprime[j][i] - s;
}
else if (j >= i) {
double s;
s = 0;
for (k = 0; k < i; k++) {
s += L[j][k] * U[k][i];
}
L[j][i] = (Aprime[j][i] - s) / U[i][i];
}
}
}
else if (j >= i)
是不必要的,可以只用 else
代替.但是,我们可以拆分 j
循环成两个循环,这样都不需要 if/else
:
// fix2.c -- split up j's loop to eliminate if/else inside
double U[n][n];
double L[n][n];
double Aprime[n][n];
for (i = 0; i < n; i++) {
for (j = 0; j <= i; j++) {
double s = 0;
for (k = 0; k < j; k++)
s += L[j][k] * U[k][i];
U[j][i] = Aprime[j][i] - s;
}
for (; j < n; j++) {
double s = 0;
for (k = 0; k < i; k++)
s += L[j][k] * U[k][i];
L[j][i] = (Aprime[j][i] - s) / U[i][i];
}
}
U[i][i]
在秒中不变 j
循环,所以我们可以预先保存它:
// fix3.c -- save off value of U[i][i]
double U[n][n];
double L[n][n];
double Aprime[n][n];
for (i = 0; i < n; i++) {
for (j = 0; j <= i; j++) {
double s = 0;
for (k = 0; k < j; k++)
s += L[j][k] * U[k][i];
U[j][i] = Aprime[j][i] - s;
}
double Uii = U[i][i];
for (; j < n; j++) {
double s = 0;
for (k = 0; k < i; k++)
s += L[j][k] * U[k][i];
L[j][i] = (Aprime[j][i] - s) / Uii;
}
}
对矩阵的访问可能是缓存性能最差的方式。因此,如果可以翻转维度的分配,则可以大大节省内存访问:
// fix4.c -- transpose matrix coordinates to get _much_ better memory/cache
// performance
double U[n][n];
double L[n][n];
double Aprime[n][n];
for (i = 0; i < n; i++) {
for (j = 0; j <= i; j++) {
double s = 0;
for (k = 0; k < j; k++)
s += L[k][j] * U[i][k];
U[i][j] = Aprime[i][j] - s;
}
double Uii = U[i][i];
for (; j < n; j++) {
double s = 0;
for (k = 0; k < i; k++)
s += L[k][j] * U[i][k];
L[i][j] = (Aprime[i][j] - s) / Uii;
}
}
更新:
In the Op's first k-loop its
k<j
and in the 2ndk<i
don't you have to fix that?
是的,我已经修好了。 fix1.c
的变化太难看了,所以我删除了它并将更改应用到 fix2-fix4
在哪里很容易做到。
更新#2:
These variables are all local to the function.
如果你的意思是它们是函数范围的[没有 static
],这表示矩阵不能太大,因为除非代码增加堆栈大小,否则它们会被限制在堆栈大小限制内(例如 8 MB)
尽管矩阵看起来是 VLA [因为 n
是小写的],我忽略了这一点。您可能想尝试使用固定维度数组的测试用例,因为我相信它们可能会更快。
此外,如果矩阵是函数范围的,并且想要并行化事物,您可能需要做(例如)#pragma omp shared(Aprime) shared(U) shared(L)
.
对缓存的最大拖累是计算 s
的循环.在 fix4
, 我能够访问 U
缓存友好,但是 L
访问很差。
I'd need to post a whole lot more if I did include the external context
我也猜到了,所以我推测性地进行了矩阵维度交换,不知道还有多少其他代码需要更改。
我创建了一个新版本来更改 L
上的尺寸回到原来的方式,但将交换的版本保留在其他版本上。这为所有矩阵提供了最佳缓存性能。也就是说,大多数矩阵访问的内部循环使得每次迭代都沿着缓存行递增。
事实上,试一试。它可能会将事情改进到不需要并行的程度。我怀疑代码无论如何都是内存限制的,所以并行可能没有多大帮助。
// fix5.c -- further transpose to fix poor performance on s calc loops
//
// flip the U dimensions back to original
double U[n][n];
double L[n][n];
double Aprime[n][n];
double *Up;
double *Lp;
double *Ap;
for (i = 0; i < n; i++) {
Ap = Aprime[i];
Up = U[i];
for (j = 0; j <= i; j++) {
double s = 0;
Lp = L[j];
for (k = 0; k < j; k++)
s += Lp[k] * Up[k];
Up[j] = Ap[j] - s;
}
double Uii = Up[i];
for (; j < n; j++) {
double s = 0;
Lp = L[j];
for (k = 0; k < i; k++)
s += Lp[k] * Up[k];
Lp[i] = (Ap[j] - s) / Uii;
}
}
即使您真的需要原始尺寸,根据其他代码,您也可以转置进入并转置回去。这将使其他代码保持不变,但是,如果此代码确实是一个瓶颈,则额外的转置操作可能足够小,值得这样做。
更新 #3:
我对所有版本都运行了基准测试。以下是 n
的耗时和相对于原始的比率等于 1037:
orig: 1.780916929 1.000x
fix1: 3.730602026 0.477x
fix2: 1.743769884 1.021x
fix3: 1.765769482 1.009x
fix4: 1.762100697 1.011x
fix5: 0.452481270 3.936x
比率越高越好。
无论如何,这是我能做的极限了。那么,祝你好运......
关于c++ - 是否可以并行化这个 for 循环?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39403215/
我是 python 的新手。我试图找到我的文本的频率分布。这是代码, import nltk nltk.download() import os os.getcwd() text_file=open(
我对安卓 fragment 感到困惑。我知道内存 fragment 但无法理解什么是 android fragment 问题。虽然我发现很多定义,比如 Android fragmentation re
尝试对 WordPress 进行 dockerise 我发现了这个场景: 2个数据卷容器,一个用于数据库(bbdd),另一个用于wordpress文件(wordpress): sudo docker
这个问题已经有答案了: From the server is there a way to know that my page is being loaded in an Iframe (1 个回答)
我正在玩小型服务器,试图对运行在其上的服务进行docker化。为简化起见,假设我必须主要处理:Wordpress和另一项服务。 在Docker集线器上有许多用于Wordpress的图像,但是它们似乎都
我想要发生的是,当帐户成功创建后,提交的表单应该消失,并且应该出现一条消息(取决于注册的状态)。 如果成功,他们应该会看到一个简单的“谢谢。请检查您的电子邮件。” 如果不是,那么他们应该会看到一条适当
就是这样,我需要为客户添加一个唯一标识符。通过 strip 元数据。这就是我现在完全构建它的方式,但是我只有最后一部分告诉我用户购买了哪个包。 我试着看这里: Plans to stripe 代码在这
我有一个类将执行一些复杂的操作,涉及像这样的一些计算: public class ComplexAction { public void someAction(String parameter
这个问题已经有答案了: maven add a local classes directory to module's classpath (1 个回答) 已关闭10 年前。 我有一些不应更改的旧 E
我使用 fragment 已经有一段时间了,但我经常遇到一个让我烦恼的问题。 fragment 有时会相互吸引。现在,我设法为此隔离了一个用例,它是这样的: Add fragment A(也使用 ad
我的 html 中有一个 ol 列表,上面有行条纹。看起来行条纹是从数字后面开始的。有没有办法让行条纹从数字开始? 我已经包含了正在发生的事情的片段 h4:nth-child(even) {
如何仅使用 css 将附加图像 html 化? 如果用纯 css 做不到,那我怎么能至少用一个图像来做 最佳答案 这不是真正的问题,而是您希望我们为您编写代码。我建议您搜索“css breadcrum
以下是 Joshua 的 Effective Java 的摘录: If you do synchronize your class internally, you can use various te
在这里工作时,我们有一个框向业务合作伙伴提供 XML 提要。对我们的提要的请求是通过指定查询字符串参数和值来定制的。其中一些参数是必需的,但很多不是。 例如,我们要求所有请求都指定一个 GUID 来标
我有 3 个缓冲区,其中包含在 32 位处理器上运行的 R、G、B 位数据。 我需要按以下方式组合三个字节: R[0] = 0b r1r2r3r4r5r6r7r8 G[0] = 0b g1g2g3g4
我最近发现了关于如何使用 History.js、jQuery 和 ScrollTo 通过 HTML5 History API 对网站进行 Ajax 化的要点:https://github.com/br
我们有一个 Spring Boot 应用程序,由于集成需要,它变得越来越复杂——比如在你这样做之后发送一封电子邮件,或者在你之后广播一条 jms 消息等等。在寻找一些更高级别的抽象时,我遇到了 apa
我正在尝试首次实施Google Pay。我面临如何指定gateway和gatewayMarchantId的挑战。 我所拥有的是google console帐户,不知道在哪里可以找到此信息。 priva
昨天下午 3 点左右,我为两个想要从一个 Azure 帐户转移到另一个帐户的网站设置了 awverify 记录。到当天结束时,Azure 仍然不允许我添加域,所以我赌了一把,将域和 www 子域重新指
我正在使用terms facet在elasticsearch服务器中获取顶级terms。现在,我的标签"indian-government"不被视为一个标签。将其视为"indian" "governm
我是一名优秀的程序员,十分优秀!