如何在 Raku 中模拟 wc -l

The*_*ete 9 perl raku

在 perl 5 中,您可以wc -l使用 oneliner进行模拟:

perl -lnE 'END {say $.}' test.txt

如何在 Raku 上实现此功能

如果您尝试实现这一点:

raku -e 'say "test.txt".IO.open.lines.elems'

事实证明它很慢并且使用了大量内存

重现的信息:

$ wget http://eforexcel.com/wp/wp-content/uploads/2017/07/1500000%20Sales%20Records.zip
$ unzip "1500000 Sales Records.zip"
$ mv "1500000 Sales Records.csv" part.txt
$ for i in `seq 1 10`; do cat part.txt >> test.txt ; done
$ du -sh test.txt
1.8G    test.txt

$ time wc -l test.txt
15000000 test.txt

real    0m0,350s
user    0m0,143s
sys     0m0,205s

$ time perl -lnE 'END { say $. }' test.txt
15000001

real    0m1,981s
user    0m1,719s
sys     0m0,256s

$ time raku -e 'say "test.txt".IO.open.lines.elems'
15000001

real    2m51,852s
user    0m25,129s
sys     0m6,378s

# Using swap (maximum uses 2.2G swap):
# Before `raku -e ''`

$ free -m
              total        used        free      shared  buff/cache   available
Mem:          15009        1695       12604         107         708       12917
Swap:          7583           0        7583

# After `raku -e ''`

$ free -m
              total        used        free      shared  buff/cache   available
Mem:          15009         752       13923          72         332       13899
Swap:          7583         779        6804

# Swap not used
$ time raku -ne '++$ andthen END .say' test.txt
15000001

real    1m44,906s
user    2m14,165s
sys     0m0,653s

$ raku -v
This is Rakudo version 2019.11 built on MoarVM version 2019.11
implementing Perl 6.d.
Run Code Online (Sandbox Code Playgroud)

rai*_*iph 8

与以下相比,仍然可能很慢perl但值得比较的一种选择:

raku -ne '++$ andthen END .say' test.txt
Run Code Online (Sandbox Code Playgroud)

l命令行选项是多余的。

$ 是匿名状态标量。

andthen测试其 lhs 是否已定义,如果已定义,则将该值设置为主题 ( $_),然后评估其 rhs。

END类似于perlEND。请注意,它返回Nil到 ,andthen但这在这里无关紧要,因为我们使用END's 语句来实现它的副作用。

有几件事会影响此代码的速度。我能想到的一些事情:

  • 编译器启动开销。忽略正在使用的任何模块,raku编译器 Rakudo 在典型硬件上的启动开销约为十分之一秒,而perl.

  • “线”的概念。在 中perl,行处理的默认概念是读取一系列字节,其中一些字节代表行结束。在 中raku,行处理的默认概念是读取 UTF-8 字符串,其中一些表示行结束。因此perl只会产生 ASCII(或扩展 ASCII)解码器raku的读取开销,而产生 UTF-8 解码器的读取开销。

  • 编译器优化。 perl通常优化到最大值。如果perl -lnE 'END {say $.}' test.txt利用一些巧妙的优化,我不会感到惊讶。相比之下,Rakudo 优化的工作相对来说还处于起步阶段。

对于我上面提到的三点中的第一点和最后一点,我认为任何人都可以做的唯一事情就是等待 N 年和/或为编译器的改进做出贡献。

将有一种方法可以解决 raku 默认的 UTF-8。也许像下面这样的东西已经是可行的,并且比 raku 的默认值快得多,至少忽略使用名为 的模块的开销foo

raku -Mfoo -ne '++$ andthen END .say' test.txt
Run Code Online (Sandbox Code Playgroud)

其中 modulefoo将文件 I/O 的默认编码切换为 ASCII 或可用编码中的任何内容。

我还没有检查过这在当前的 Rakudo 中实际上是可行的,但如果不是,我会感到惊讶。