- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
所以我目前正在尝试为一些 2d ndarray 做类似 A**b 的事情,并为 Python 并行做一个双 b。我想通过使用 OpenMP 的 C 扩展来做到这一点(是的,我知道,有 Cython 等,但在某些时候,我总是遇到那些“高级”方法的麻烦......)。
所以这是我的 gaussian.so 的 gaussian.c 代码:
void scale(const double *A, double *out, int n) {
int i, j, ind1, ind2;
double power, denom;
power = 10.0 / M_PI;
denom = sqrt(M_PI);
#pragma omp parallel for
for (i = 0; i < n; i++) {
for (j = i; j < n; j++) {
ind1 = i*n + j;
ind2 = j*n + i;
out[ind1] = pow(A[ind1], power) / denom;
out[ind2] = out[ind1];
}
}
(A 是一个正方形双矩阵,out 具有相同的形状,n 是行数/列数)所以重点是更新一些对称距离矩阵 - ind2 是 ind1 的转置索引。
我使用 gcc -shared -fopenmp -o gaussian.so -lm gaussian.c
编译它。我通过 Python 中的 ctypes 直接访问函数:
test = c_gaussian.scale
test.restype = None
test.argtypes = [ndpointer(ctypes.c_double,
ndim=2,
flags='C_CONTIGUOUS'), # array of sample
ndpointer(ctypes.c_double,
ndim=2,
flags='C_CONTIGUOUS'), # array of sampl
ctypes.c_int # number of samples
]
只要我对 #pragma 行进行注释,函数“test”就可以顺利运行 - 否则它会以错误号 139 结束。
A = np.random.rand(1000, 1000) + 2.0
out = np.empty((1000, 1000))
test(A, out, 1000)
当我将内部循环更改为仅打印 ind1 和 ind2 时,它可以顺利并行运行。它也有效,当我只访问 ind1 位置并单独留下 ind2 (即使是并行的)!我在哪里搞砸了内存访问?我该如何解决这个问题?
谢谢!
更新:好吧,我想这会进入 GIL,但我还不确定...
更新:好的,我现在很确定,是邪恶的 GIL 杀了我,所以我改变了例子:
我现在有 gil.c:
#include <Python.h>
#define _USE_MATH_DEFINES
#include <math.h>
void scale(const double *A, double *out, int n) {
int i, j, ind1, ind2;
double power, denom;
power = 10.0 / M_PI;
denom = sqrt(M_PI);
Py_BEGIN_ALLOW_THREADS
#pragma omp parallel for
for (i = 0; i < n; i++) {
for (j = i; j < n; j++) {
ind1 = i*n + j;
ind2 = j*n + i;
out[ind1] = pow(A[ind1], power) / denom;
out[ind2] = out[ind1];
}
}
Py_END_ALLOW_THREADS
}
使用 gcc -shared -fopenmp -o gil.so -lm gil.c -I/usr/include/python2.7 -L/usr/lib/python2.7/-lpython2.7 编译
和相应的 Python 文件:
import ctypes
import numpy as np
from numpy.ctypeslib import ndpointer
import pylab as pl
path = '../src/gil.so'
c_gil = ctypes.cdll.LoadLibrary(path)
test = c_gil.scale
test.restype = None
test.argtypes = [ndpointer(ctypes.c_double,
ndim=2,
flags='C_CONTIGUOUS'),
ndpointer(ctypes.c_double,
ndim=2,
flags='C_CONTIGUOUS'),
ctypes.c_int
]
n = 100
A = np.random.rand(n, n) + 2.0
out = np.empty((n,n))
test(A, out, n)
这给了我
Fatal Python error: PyEval_SaveThread: NULL tstate
Process finished with exit code 134
现在不知何故它似乎无法保存当前线程 - 但是 API 文档没有在这里详细介绍,我希望在编写我的 C 函数时可以忽略 Python,但这似乎很困惑: (有什么想法吗?我发现这很有帮助:GIL
最佳答案
您的问题比您想象的要简单得多,并且不以任何方式涉及 GIL。当您通过 ind2
访问它时,您正在对 out[]
进行越界访问,因为 j
很容易变得大于 n
。原因很简单,您没有对并行区域应用任何数据共享子句,并且除 i
之外的所有变量都保持共享(按照 OpenMP 中的默认设置),因此会出现数据竞争 - 在这种情况下多个同时增量由不同的线程完成。 j
太大对于 ind1
来说问题不大,但对于 ind2
则不是,因为太大的值会乘以 n
因此变得太大了。
只需将 j
、ind1
和 ind2
设置为私有(private)即可:
#pragma omp parallel for private(j,ind1,ind2)
for (i = 0; i < n; i++) {
for (j = i; j < n; j++) {
ind1 = i*n + j;
ind2 = j*n + i;
out[ind1] = pow(A[ind1], power) / denom;
out[ind2] = out[ind1];
}
}
更好的是,在使用它们的范围内声明它们。这会自动将它们设为私有(private):
#pragma omp parallel for
for (i = 0; i < n; i++) {
int j;
for (j = i; j < n; j++) {
int ind1 = i*n + j;
int ind2 = j*n + i;
out[ind1] = pow(A[ind1], power) / denom;
out[ind2] = out[ind1];
}
}
关于python - OpenMP、Python、C 扩展、内存访问和邪恶的 GIL,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21523660/
我已经配置了我的环境,以便我可以将适当制作的 .png 文件加载到如下定义的图像中: boost::gil::rgb8_image_t input; 但是我如何加载任何典型类型的 pn
我已经配置了我的环境,以便我可以将适当制作的 .png 文件加载到如下定义的图像中: boost::gil::rgb8_image_t input; 但是我如何加载任何典型类型的 pn
它本质上是这个问题的延伸 - Usage of threadpoolexecutor in conjunction with cython's nogil 在这种情况下,我的 getArea2() 方
我意识到写信给 gil::color_converted_view不影响底层 View 的数据。我想知道这是否正确? 例如,假设我想编写一个程序,获取红色 channel 的值并将蓝色 channel
我有一个 Python 程序,因为它太大了,这里是它的源代码的链接: Link 当我在 Mac 上运行它时,有时会遇到这个奇怪的异常: Fatal Python error: PyEval_Resto
Wikipedia文章Global interpreter lock指示Raku具有全局解释器锁。 这与Curtis Poe's response到Are any companies planning
如果一个线程正在等待阻塞 I/O,Ruby 互斥体是否允许两个线程同时执行? 这是我对 GIL 如何用于 MRI 的理解。我很好奇互斥锁和 GIL 之间有什么区别吗? 最佳答案 是的,这有效。正因为如
我不太确定GIL是如何实现的,但理论上,如果我使用pyinstaller将python脚本编译成exe ,还会实现GIL吗?有什么办法可以绕过这个吗? 最佳答案 如果您使用 CPython(“标准 P
我将 Python 3.2 嵌入到 C++ 应用程序中,并且我有几个在程序中不同时间运行的子解释器(由 Py_NewInterpreter 创建)。他们在不同时间获取和释放 GIL,但当我想销毁其中一
阅读各种解释 GIS 和 Python 线程的文章后,Are locks unnecessary in multi-threaded Python code because of the GIL?这是
有没有办法剖析 python 进程对 GIL 的使用情况?基本上,我想知道持有 GIL 的时间百分比。该进程是单线程的。 我的动机是我有一些用 Cython 编写的代码,它使用 nogil。理想情况下
我正在重新表述我的问题,因为我认为很多人认为这是“Python 有线程吗”的问题。确实如此,但 CPython 也有 GIL,它在任何给定时间都不会调度多个线程。这使得 CPython 线程对于 CP
我想将我的单线程应用程序与工作线程数分开。只有 1 个问题 - 这个 Action 的表现如何?如果 GIL 阻止 python 同时执行超过 1 个线程,我会有任何 yield 吗? 另一点(从 c
在 python 中,我定义了一个全局变量,它被不同的线程读取/递增。由于 GIL,如果不使用任何类型的锁定机制,这是否会导致问题? 最佳答案 GIL 只要求解释器在另一个线程接管之前完全执行单个字节
假设我有一个线程和程序的主要部分。由于 GIL,一个线程应该一次工作(而不是同时工作)吗?但是,如果其中一个线程是一个无限循环(或两者都是无限循环)怎么办? 这两个进程会并行运行吗? def test
我正在阅读有关 GIL 的内容,但它从未真正指定它是否包含主线程(我假设是这样)。我问的原因是因为我有一个带有修改字典的线程设置的程序。主线程根据玩家输入添加/删除,而线程循环数据更新和更改数据。 然
我试图找到一个函数来告诉我当前线程是否具有全局解释器锁。 Python/C-API 文档似乎没有包含这样的函数。 我目前的解决方案是使用 PyGILState_Ensure() 获取锁,然后使用 Py
CPython 使用 Global Interpreter Lock . Linux 已删除 Big Kernel Lock 的所有痕迹.这些锁的替代品是什么?一个系统如何才能充分利用一个真正的多核或
CPU-bound(计算密集型) 和I/O bound(I/O密集型) 计算密集型任务(CPU-bound) 的特点是要进行大量的计算,占据着主要的任务,消耗CPU资源,一直处于满负荷状态。比如复
我的部分工作需要大量计算,但它们通常相当简单,原则上可以很容易地与 Cython 的 prange 并行完成,需要 nogil。但是,鉴于我尝试编写 Cython 代码,重点是将 cdef 类作为构建
我是一名优秀的程序员,十分优秀!