我已经在Python中开发了性能至关重要且占用大量CPU的应用程序。为了达到可接受的性能,我使用了PyPy以及os.fork生成的多个进程。总体而言,我现在对性能已接近编译语言感到满意。但是我最初必须使用很多GUID:
import uuid
print(str(uuid.uuid4()))
生成UUID。但是分析显示,UUID生成约占总运行时间的20%。这似乎是由于对os.urandom()
中的uuid.uuid4()
的调用在某些系统(包括OS X)上似乎很慢。然后,我将os.urandom()
替换为random.getrandbits()
:
import random
str(UUID(int=random.getrandbits(128), version=4))
哪个快。但是现在事实证明,我的并行运行的工作进程会大量生成重复的GUID。
我怀疑python的伪数字生成器是在当前时间播种的,这就是为什么不同的进程将生成相同的随机数的原因。我可以考虑的一种可能的解决方法是将进程ID包含在数字生成器的种子中。但是由于我不确定在内部如何构建uuid和random软件包,因此我不确定这是否足以防止冲突。我发现一些替代的UUID实现被编写为c扩展,但是由于PyPy,我无法使用它们。
由于某些库,我仅在此项目中使用python,而在python中进行编码的经验很少。
更新:
现在,我在分叉之后添加了seed(SystemRandom().getrandbits(128))
。因此,使用/ dev / urandom播种PRNG。到目前为止,这似乎工作良好。
我喜欢用rossum提出的将子进程与主进程RNG一起播种的想法。但是现在我想到了,我想使用OS的RNG播种RNG应该更加安全。特别是因为我的应用程序还可以在多个节点上分布式运行。恕我直言,用MAC地址和时间戳为初始RNG播种,然后使用rossums建议也可以。
答案 0 :(得分:2)
之所以发生这种情况,是因为进程派生导致每个进程具有相同内存的副本,包括相同PRNG状态的副本。相反,用SystemRandom
进行分叉后重新播种解决了此问题,因为SystemRandom
提供的随机数是操作系统的全局变量,而不是各个进程的全局变量。
答案 1 :(得分:1)
请注意,以这种方式使用random.random
仍然可能不安全。它使用的是相当弱的,可预测的用户空间PRNG。我的第一个建议是简单地替换
import random
使用
from random import SystemRandom
random = SystemRandom()
但是,如果仍然很慢,我确实做了一个确定性的用户空间CSPRNG,您可以在这里尝试:https://pypi.org/project/streamrandom/
这甚至包括UUID
生成功能,您可以像这样使用它:
import os
from streamrandom import StreamRandom, stream_from_seed
random = StreamRandom(stream_from_seed(os.random(128).decode("charmap")))
uuid = random.uuid4()