【问题标题】:Efficient way to generate and use millions of random numbers in Python在 Python 中生成和使用数百万个随机数的有效方法
【发布时间】:2011-12-20 18:28:47
【问题描述】:

我正在进行编程项目,该项目涉及在 Python 中进行的一些相当广泛的蒙特卡洛模拟,因此会生成大量随机数。几乎所有的,如果不是全部的话,将能够由 Python 的内置随机模块生成。

我是一个编码新手,不熟悉高效和低效的做事方式。将所有随机数生成为一个列表,然后遍历该列表,或者每次调用函数时生成一个新的随机数,这将处于一个非常大的循环中,是不是更快?

或者其他一些无疑更聪明的方法?

【问题讨论】:

  • 如果您使用的是 Linux,将一堆数字 /dev/random 读入一个文件,然后再使用,速度会更快,而且数字的质量可能会更好。并不是说 Python 的随机生成器不好。
  • @kaloyan:如果 OP 使用 random.SystemRandom 而不是 random 模块,那么它将在 *nix 上使用 /dev/urandom,在 Windows 上使用 CryptGenRandom。这绰绰有余。
  • 一个更快的方法是使用 NumPy 的 random.randint 方法。在 Numpy 中(在我相当旧的机器上)生成一个包含 100 万个随机整数的数组需要 45 毫秒,而在 Python 循环中需要 5.5 秒。
  • 您打算多久使用一次?或者 - 您的蒙特卡洛模拟有多广泛(慢)?如果每次运行需要 24 小时,那么生成 1M 个数字是否需要毫秒或秒并不重要。仅在重要时才优化某些内容...
  • @FrerichRaabe 我知道我的特定应用程序,我不会打扰 - 我愿意接受相当粗略的随机性。

标签: python random


【解决方案1】:

每次生成一个随机数。由于循环的内部工作只关心单个随机数,因此在循环内部生成并使用它。

例子:

# do this:
import random

for x in xrange(SOMEVERYLARGENUMBER):
    n = random.randint(1,1000) # whatever your range of random numbers is
    # Do stuff with n

# don't do this:
import random

# This list comprehension generates random numbers in a list
numbers = [random.randint(1,1000) for x in xrange(SOMEVERYLARGENUMBER)]

for n in numbers:
    # Do stuff with n

显然,实际上这并不重要,除非您要处理数十亿次迭代,但如果您一次只使用一个,为什么还要生成所有这些数字呢?

【讨论】:

  • 重要的旁注:如果你生成数十亿个数字并将它们存储在一个列表中,你最终会耗尽内存。如果您按需生成这些数字,这不是问题。因此,对于大量数字,您必须在需要时生成它们。
  • random.randint() 在我的硬件上只能产生大约 300K 个数字/秒。这很慢。
  • 如果您只使用生成器而不是列表,您可以使用don't do this 方法,即将[random.randint..] 更改为(random.randint..)
  • 是的,但它不会真的那么可读。记住:"Readability counts."
【解决方案2】:
import random
for x in (random.randint(0,80) for x in xrange(1000*1000)):
    print x

括号之间的代码一次只会生成一个项目,所以它是内存安全的。

【讨论】:

    【解决方案3】:

    Python 内置 random 模块,例如random.random()random.randint(),(一些分布也可用,你可能想要高斯分布)大约 300K 样本/秒。

    由于您正在进行数值计算,因此您可能无论如何都使用numpy,如果您一次制作一个随机数数组而不是一次制作一个数字,并且可以提供更广泛的分布选择,则可以提供更好的性能。 60K/s * 1024(数组长度),即 ~60M 个样本/s。

    您还可以在 Linux 和 OSX 上阅读/dev/urandom。我的硬件/软件(osx 笔记本电脑)管理 ~10MB/s。

    当然必须有更快的方法来生成大量随机数,例如:

    from Crypto.Cipher import AES
    from Crypto.Util import Counter
    import secrets
    
    aes = AES.new(secrets.token_bytes(16), AES.MODE_CTR, secrets.token_bytes(16), counter=Counter.new(128))
    data = "0" * 2 ** 20
    with open("filler.bin", "wb") as f:
        while True:
            f.write(aes.encrypt(data))
    

    这会在 i5-4670K 的单核上产生 200MB/s

    像 aes 和河豚这样的常用密码在我的堆栈上管理 112MB/s 和 70MB/s。此外,现代处理器使 aes 的速度更快,最高可达 700MB/s see this link to test runs on few hardware combinations。 (编辑:链接断开)。您可以使用较弱的 ECB 模式,前提是您向其中提供不同的输入,并实现高达 3GB/s 的速度。

    流密码更适合该任务,例如RC4 在我的硬件上的最高速度为 300MB/s,您可能会从最流行的密码中获得最佳结果,因为我们会花更多的精力来优化这些密码和软件。

    【讨论】:

      【解决方案4】:

      高效、快速地生成 10M 随机数的代码:

      随机导入 l=10000000 列表随机=[] 对于范围 (l) 内的 i: 值=随机.randint(0,l) listrandom.append(值) 打印列表随机

      所花费的时间包括在屏幕上打印时滞后的 I/O 时间:

      真正的 0m27.116s 用户 0m24.391s 系统 0m0.819s

      【讨论】:

        【解决方案5】:

        使用 Numpy -

        import numpy as np
        np.random.randint(low="put the range like 1 to 100, so put '1' in 
        low",high="100",size="1000000")
        

        【讨论】:

          猜你喜欢
          • 2011-06-05
          • 1970-01-01
          • 2017-02-14
          • 1970-01-01
          • 1970-01-01
          • 2015-12-19
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多