【问题标题】:bash/python/perl/etc. Fast generation of file with many pairs of random, alphabetic stringsbash/python/perl/等。快速生成具有多对随机字母字符串的文件
【发布时间】:2018-11-09 20:23:53
【问题描述】:

我的问题

我很惊讶在这里没有找到类似的问题。也许我需要学习如何更好地搜索。主要是,我想弄清楚我的算法的哪一部分是慢的,以及是否有其他更快的方法来实现我的目标。

我正在尝试生成一个包含 1 亿对随机字母字符串的文件。这些随机字符串可以包含空格。随机词周围有一些真实的、固定的词。我想要的输出的一个例子是

rrn TRY gy q OFTEN
ibh TRY mpdw OFTEN
bnq TRY nbjw OFTEN
tky TRY tedr OFTEN
c r TRY  fdv OFTEN
cvs TRY dusr OFTEN
ppd TRY qhrc OFTEN
...

我希望能够在 Linux 脚本语言中执行此操作(我实际上使用的是 Cygwin),因此bashpythonperl 等中的答案将是首选。但是,如果我要使用 C++Java 或其他方式大幅提高速度,我愿意。

目前,我的脚本通过

运行
$ ./create_big_file.sh 100000000

bash 脚本如下。我已经改变了一些东西,以免硬编码对的数量。

我的可执行代码

#!/bin/bash
#
# @file create_big_file.sh

n_lines=$1
filename="big_file_${n_lines}.out"

n_lett_rand_str1=3 # originally had 5, tried 3 for speed
n_lett_rand_str2=4 # originally had 10, tried 4 for speed

between=" TRY "
after=" OFTEN"

while [ $n -lt $n_lines ]; do
  n_lett_rand_str1=3
  n_lett_rand_str2=4

  random_str1=$(cat /dev/urandom | tr -dc 'a-z ' | \
fold -w $n_lett_rand_str1 | head -n 1)

  random_str2=$(cat /dev/urandom | tr -dc 'a-z ' | \
fold -w $n_lett_rand_str2 | head -n 1)

  echo "${random_str1}${between}${random_str2}${after}" >> "$filename"

  n=$(($n+1))

done #endof:  while [ $n -lt $n_lines ]

正如预期的那样,我的运行时间大致呈线性扩展,但每次迭代所花费的时间对我来说似乎很长。如果我估计纯线性时间,我计算出它需要 265.0 天。如果我使用完整的t=a*exp[x,b] 拟合,我计算出 1.016 年。如果我只想要一百万行,大约需要 2-3 天。

问题

我认为必须有一种方法来做我想做的事情,但速度更快。有谁知道在更短的时间内创建这样一个文件的方法?如果能在 4 小时内搞定,我愿意满足 100 万行,但我希望能在不到一天的时间内搞定 1 亿行。

附:这不是家庭作业;我正在做一些文本分析。


我的研究

$ time ./create_big_file.sh 10

real    0m2.487s
user    0m1.115s
sys     0m1.950s

$ time ./create_big_file.sh 100

real    0m22.356s
user    0m11.764s
sys     0m16.517s

$ tail -2 big_file_100.out
mri TRY nzeo OFTEN
hev TRY uqdf OFTEN

$ time ./create_big_file.sh 500

real    1m52.143s
user    0m57.347s
sys     1m19.405s

$ time ./create_big_file.sh 1000

real    3m50.129s
user    1m58.697s
sys     2m45.612s

Wolfram|Alpha 中找到的时间与行数的拟合是

t(x) = 0.11905 x1.02845

我尝试替换

random_str1=$(cat /dev/urandom | tr -dc 'a-z ' | \
fold -w $n_lett_rand_str1 | head -n 1)

random_str1=$(echo $RANDOM | tr '[0-9]' '[a-z ]')

并对random_str2 进行了相同的更改。这给了我两个最多 5 个字母的字符串。但是,我在运行时间方面没有显着差异。

比较

我运行脚本时没有随机生成任何字符串。我注释掉了任何与随机的东西有关的东西,然后运行了 while 循环

echo "${between}${after}"
n=$(($n+1))

在里面,我的运行时编号是(格式:{n_lines, n_seconds}

{{10, 0.049},{100, 0.097},{500, 0.157},{1000,0.263}, {10000, 1.996}, {100000, 19.222}}

将增长顺序设为 (source)

t(x) = 0.000243745 x0.979367

这让我很确定是随机因素导致了问题 - 比如每个随机问题 0.2 秒。

编辑 “随机”不必非常随机。我基本上希望它不会以 10-20 行的顺序重复(除了非常罕见)。同样,它是用于文本处理的东西。感谢@zdim 要求澄清。

这可能只会在六个月内运行一次或两次。

【问题讨论】:

  • 嗨,当 bash 变慢时,我已经多次将 bash 脚本重写为 Perl。性能大大提高。那我就不评论算法本身了,只评论实现语言。你可以看看这个blog.famzah.net/2016/02/09/…
  • 是的,最大的消费者将是“随机的东西”,以及所有这些额外的过程(管道!)。下一个消费者将是 I/O,最后我怀疑 shell 的选择。所以:尝试一些简单的随机性(重要:这需要有多好?)。并使用不同的工具。鉴于您希望我会说脚本语言应该这样做,但当然 C/C++ 应该更好。另外:你能预先计算一个准随机序列吗?这是否需要重复运行,经常......?
  • 我只是用 Perl 重写了它,用 3 和 4 创建 100_000_000 行大约需要 3 秒。
  • @zdim :感谢您的帮助。我确实找到了使用准随机序列的解决方案。 (我用base64 替换了cat,写了两个包含100 万个字符串的数组,然后将它们读回。)这行得通,但花了20 多分钟。我似乎记得bash 有一个基于底层 RAM 的数组大小限制。 This link 说 1.3 GB 内存导致大约 1800 万的限制。 @simbabque 有一个更快的解决方案,但欢迎您发布您的想法作为完整性的答案。
  • @zdim :我还有一个 n00b 问题。 “管道!”是什么意思?

标签: python bash perl random file-io


【解决方案1】:

您可以在 Perl 中执行此操作,它会在几秒钟内运行 1 亿行。

use strict;
use warnings;
use feature 'say';

# read command line arguments
my ( $first_length, $second_length, $lines, $first_word, $second_word ) = @ARGV;
$first_word //= 'TRY';
$second_word //= 'OFTEN';

# define your alphabet of random characters
my @alphabet = ( 'a' .. 'z', q{ } );
my $max_rand = scalar @alphabet;

foreach my $i ( 1 .. $lines ) {
    say join(
        q{ },
        ( join q{}, map { $alphabet[ int rand $max_rand ] } 1 .. $first_length ),
        $first_word,
        ( join q{}, map { $alphabet[ int rand $max_rand ] } 1 .. $second_length ),
        $second_word,
    );
}

这个程序需要三个或五个参数:

$ perl foo.pl 3 4 100000000 TRY OFTEN

在我的机器上,生成完整的 100M 行大约需要三秒钟。输出如下所示:

wab TRY mcqb OFTEN
tdb TRY tobw OFTEN
rlf TRY lg v OFTEN
ofn TRY oxdf OFTEN
o j TRY vcfp OFTEN
ffv TRY doud OFTEN
lvl TRY ckci OFTEN
xqh TRY wnaa OFTEN
fhj TRY  pmp OFTEN
oxe TRY swyi OFTEN

【讨论】:

  • 已验证!我运行了一百万个字符串来与我的 bash 数组解决方案进行比较(由于数组大小问题,它无法达到 1 亿个。)输入:time perl foo.pl 3 4 1000000 > big_file.out 输出:real 0m3.170suser 0m3.135ssys 0m0.015s。我的电脑显然比你的慢,但解决方案很棒!
  • @bballdave025 是的,这就是基准测试的问题。 ;)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-04-24
  • 2015-07-17
  • 2010-09-08
  • 1970-01-01
  • 2012-12-29
相关资源
最近更新 更多