如何使独立编译的 cython 包使用共享随机数生成器?
How do I make independently compiled cython packages use a shared random number generator?
我有一个实验性的编程语言,程序被编译成 c。我写了一个 cython 包装器,它包装了编译后的 c 代码,并允许从 python 调用它。这使您可以在 python 中将编译后的程序用作快速低级函数。通常情况下,我们希望在同一个 python 程序中使用多个这样的程序。那么每个程序生成和导入的流水线为:
- 使用编译器将程序编译为 c。
- 使用 gcc 将 c 代码编译为 .so 共享对象。
- 生成一个 .pyx 包装器,它可以访问我们想要从 python 使用的 c 函数。
- 用 cythonize 编译 .pyx 包装器生成 .so.
- 使用 python 的导入功能导入 .so 共享对象。
实际上,步骤 1-4 实际上合并为一个外部调用以使用 sys 进行调用,生成的 Makefile 执行这 4 个步骤中的每一个。这让我们可以通过使用 sys 的外部调用来调用 make,然后导入编译后的程序而无需离开 python.
编译程序可能具有概率结构。特别是,分支决策由随机数决定。为此,调用了 c 的原生
rand()
函数。当在 python 中导入包装器编译程序时,将对使用 cythonize 生成的生成的 .so 共享对象进行导入调用。到目前为止,我已经尝试调用
srand(<long int>time(NULL)
来自包装每个已编译程序的 .pyx 文件。据我所知,每个导入的 .so 都将有效地使用自己的随机数生成器。但是我根本不清楚文档是否是这种情况。
最终我希望不同的 .so 使用相同的随机数生成器,但我不知道该怎么做。任何指导将不胜感激。大部分代码太长,无法包含在此处,但如果您想查看任何片段(例如 'how do you do x component?'),我将很乐意帮忙。
即使您只能提供对 rand() 的调用将如何在使用 cythonize 生成的不同共享对象之间进行交互的解释,这也足以让我找出解决方案。
提前致谢!
我不确定 C 规范中是否明确定义了随机种子是在 .so 文件之间还是在个人之间共享(也就是说 - 我没有读过 C 标准,所以我在这里稍微猜测一下).因此,您看到的行为可能取决于您所在的平台。
这里最简单的事情是编写一个小的 Cython 模块,其唯一目的是处理随机数生成:
# cy_rand.pxd
cpdef void srand(unsigned int)
cpdef int rand()
# cy_rand.pyx
from libc cimport stdlib
cpdef void srand(unsigned int seed):
stdlib.srand(seed)
cpdef int rand():
return stdlib.rand()
我已经创建了函数 cpdef
,这样您也可以从 Python 调用它们。如果您不关心能否做到这一点,那么只需将它们设为 cdef
.
您需要以正常方式编译该模块。在你的其他模块中,你可以这样做:
cimport cy_rand
cy_rand.srand(1) # some seed
rand_val = cy_rand.rand()
这样你就知道随机数只在一个 .so 文件中生成。这增加了一个小的间接层,因此会比直接调用它稍微慢一些。因此,添加辅助函数以批量生成随机数(为了提高速度)可能是个好主意。
请注意,其他库可以自己调用 srand
或 rand
,并且因为它可能是全局状态,所以这可能会影响您 - 这是 C 标准库随机数生成器的原因之一不是很健壮...
我有一个实验性的编程语言,程序被编译成 c。我写了一个 cython 包装器,它包装了编译后的 c 代码,并允许从 python 调用它。这使您可以在 python 中将编译后的程序用作快速低级函数。通常情况下,我们希望在同一个 python 程序中使用多个这样的程序。那么每个程序生成和导入的流水线为:
- 使用编译器将程序编译为 c。
- 使用 gcc 将 c 代码编译为 .so 共享对象。
- 生成一个 .pyx 包装器,它可以访问我们想要从 python 使用的 c 函数。
- 用 cythonize 编译 .pyx 包装器生成 .so.
- 使用 python 的导入功能导入 .so 共享对象。
实际上,步骤 1-4 实际上合并为一个外部调用以使用 sys 进行调用,生成的 Makefile 执行这 4 个步骤中的每一个。这让我们可以通过使用 sys 的外部调用来调用 make,然后导入编译后的程序而无需离开 python.
编译程序可能具有概率结构。特别是,分支决策由随机数决定。为此,调用了 c 的原生
rand()
函数。当在 python 中导入包装器编译程序时,将对使用 cythonize 生成的生成的 .so 共享对象进行导入调用。到目前为止,我已经尝试调用
srand(<long int>time(NULL)
来自包装每个已编译程序的 .pyx 文件。据我所知,每个导入的 .so 都将有效地使用自己的随机数生成器。但是我根本不清楚文档是否是这种情况。
最终我希望不同的 .so 使用相同的随机数生成器,但我不知道该怎么做。任何指导将不胜感激。大部分代码太长,无法包含在此处,但如果您想查看任何片段(例如 'how do you do x component?'),我将很乐意帮忙。
即使您只能提供对 rand() 的调用将如何在使用 cythonize 生成的不同共享对象之间进行交互的解释,这也足以让我找出解决方案。
提前致谢!
我不确定 C 规范中是否明确定义了随机种子是在 .so 文件之间还是在个人之间共享(也就是说 - 我没有读过 C 标准,所以我在这里稍微猜测一下).因此,您看到的行为可能取决于您所在的平台。
这里最简单的事情是编写一个小的 Cython 模块,其唯一目的是处理随机数生成:
# cy_rand.pxd
cpdef void srand(unsigned int)
cpdef int rand()
# cy_rand.pyx
from libc cimport stdlib
cpdef void srand(unsigned int seed):
stdlib.srand(seed)
cpdef int rand():
return stdlib.rand()
我已经创建了函数 cpdef
,这样您也可以从 Python 调用它们。如果您不关心能否做到这一点,那么只需将它们设为 cdef
.
您需要以正常方式编译该模块。在你的其他模块中,你可以这样做:
cimport cy_rand
cy_rand.srand(1) # some seed
rand_val = cy_rand.rand()
这样你就知道随机数只在一个 .so 文件中生成。这增加了一个小的间接层,因此会比直接调用它稍微慢一些。因此,添加辅助函数以批量生成随机数(为了提高速度)可能是个好主意。
请注意,其他库可以自己调用 srand
或 rand
,并且因为它可能是全局状态,所以这可能会影响您 - 这是 C 标准库随机数生成器的原因之一不是很健壮...