Bash 为什么生成更多的随机数据要慢得多?

Bash 为什么生成更多的随机数据要慢得多?,bash,random,pipe,brace-expansion,Bash,Random,Pipe,Brace Expansion,我想生成大量的随机数。我编写了下面的bash命令(请注意,我在这里使用cat是为了演示;在我的实际用例中,我将数字管道化到一个流程中): 数字以很低的速度打印出来。但是,如果生成的量较小,则速度会快得多: for i in {1..9999}; do echo -e "$(cat /dev/urandom | tr -dc '0-9' | fold -w 5 | head -n 1)"; done | cat 请注意,唯一的区别是9999,而不是9999999 为什么会这样

我想生成大量的随机数。我编写了下面的bash命令(请注意,我在这里使用
cat
是为了演示;在我的实际用例中,我将数字管道化到一个流程中):

数字以很低的速度打印出来。但是,如果生成的量较小,则速度会快得多:

for i in {1..9999}; do echo -e "$(cat /dev/urandom | tr -dc '0-9' | fold -w 5 | head -n 1)"; done | cat
请注意,唯一的区别是
9999
,而不是
9999999

为什么会这样?数据是否缓冲在某个地方?是否有办法对此进行优化,以便将随机数立即输送到
cat

为什么会这样

生成
{1..9999999}
100000000个参数,然后解析它们需要bash分配大量内存。这严重阻碍了整个系统

此外,从
/dev/uradom
读取大量数据,约96%的数据通过
tr-dc“0-9”
过滤掉。这大大耗尽了熵池,并进一步阻碍了整个系统

数据是否缓冲在某个地方

每个进程都有自己的缓冲区,因此:

  • cat/dev/uradom
    正在缓冲
  • tr-dc'0-9'
    正在缓冲
  • 折叠-w5
    是缓冲
  • 磁头-n1
    正在缓冲
  • 管道的左侧(shell)有自己的缓冲区
  • 而右侧-
    | cat
    有自己的缓冲区
这是6个缓冲区。即使忽略来自
头-n1
和管道右侧
|cat
的输入缓冲,也就是4个输出缓冲区

还有,拯救动物和动物。使用
tr
为什么会这样

生成
{1..9999999}
100000000个参数,然后解析它们需要bash分配大量内存。这严重阻碍了整个系统

此外,从
/dev/uradom
读取大量数据,约96%的数据通过
tr-dc“0-9”
过滤掉。这大大耗尽了熵池,并进一步阻碍了整个系统

数据是否缓冲在某个地方

每个进程都有自己的缓冲区,因此:

  • cat/dev/uradom
    正在缓冲
  • tr-dc'0-9'
    正在缓冲
  • 折叠-w5
    是缓冲
  • 磁头-n1
    正在缓冲
  • 管道的左侧(shell)有自己的缓冲区
  • 而右侧-
    | cat
    有自己的缓冲区
这是6个缓冲区。即使忽略来自
头-n1
和管道右侧
|cat
的输入缓冲,也就是4个输出缓冲区


还有,拯救动物和动物。使用
tr为什么在循环中运行这个?您只需运行一组命令即可生成所有内容,例如:

cat /dev/urandom | tr -dc '0-9' | fold -w 5 | head -n 100000000
即,只生成单个数字流,而不是单独生成

我支持使用另一种语言来完成这项工作的建议,它应该更有效。例如,在Python中,它只是:

来自随机导入范围
对于范围内的(100000000):
打印(兰特范围(100000))

为什么要在循环中运行此操作?您只需运行一组命令即可生成所有内容,例如:

cat /dev/urandom | tr -dc '0-9' | fold -w 5 | head -n 100000000
即,只生成单个数字流,而不是单独生成

我支持使用另一种语言来完成这项工作的建议,它应该更有效。例如,在Python中,它只是:

来自随机导入范围
对于范围内的(100000000):
打印(兰特范围(100000))
@SamMason给出了迄今为止最好的答案,因为他完全取消了循环:

cat/dev/uradom | tr-dc'0-9'| fold-w 5 | head-n 100000000

不过,这仍有很大的改进空间。首先,
tr-dc'0-9'
只使用了来自/dev/uradom:-)的大约4%的内容;其次,根据这些随机数最终将如何使用,去除前导零可能会产生一些额外的开销——因此一些数字不会被解释为八进制。让我建议一个更好的选择,使用
od
命令:

outputFile=/dev/null  # For test. Replace with the real file.
count=100000000

od -An  -t u2  -w2  /dev/urandom | head -n $count >$outputFile
使用
time
命令进行的qick测试表明,这大约比
tr
版本快四倍。实际上没有必要使用“另一种语言”,因为
od
head
都经过了高度优化,而且整个过程都以本机速度运行

注意:上述命令将生成16位整数,范围从0到65535(含0到65535)。如果您需要更大的范围,那么您可以选择32位数字,这将为您提供从0到4294967295的范围:

od -An  -t u4  -w4  /dev/urandom | head -n $count >$outputFile
如果需要,最终用户可以通过模除法将其缩小到所需的大小。

@SamMason提供了迄今为止最好的解决方案,因为他完全取消了循环:

cat/dev/uradom | tr-dc'0-9'| fold-w 5 | head-n 100000000

不过,这仍有很大的改进空间。首先,
tr-dc'0-9'
只使用了来自/dev/uradom:-)的大约4%的内容;其次,根据这些随机数最终将如何使用,去除前导零可能会产生一些额外的开销——因此一些数字不会被解释为八进制。让我建议一个更好的选择,使用
od
命令:

outputFile=/dev/null  # For test. Replace with the real file.
count=100000000

od -An  -t u2  -w2  /dev/urandom | head -n $count >$outputFile
使用
time
命令进行的qick测试表明,这大约比
tr
版本快四倍。实际上没有必要使用“另一种语言”,因为
od
head
都经过了高度优化,而且整个过程都以本机速度运行

注意:上述命令将生成16位整数,范围从0到65535
od -An  -t u4  -w4  /dev/urandom | head -n $count >$outputFile