如何在Raku中模拟wc -l


9

在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.

3
您能否添加时间信息以及的实际输出wc(应该包括文件大小)。谢谢。
伊丽莎白·马蒂森

更新问题-添加了复制示例
TheAthlete

2
@TheAthlete感谢您添加信息。我认为这很可能在历史上很有趣,因为rakudo可能会在未来几年稳定缩小性能差距,因此请考虑再添加一些信息。首先,虽然很明显您正在使用最近的rakudo(因为您正在编写raku),但仍然可以raku -v输出。另外,请考虑添加当前建议的时间安排输出。另外,我可能会考虑在'ascii'本周末晚些时候切换到解码器,以创造更好的时间。
雷夫

1
附带说明:-lperl的标志会大大降低perl的速度,在这种情况下它没有用。在我的计算机上,如果文件的行长度随机且行数约为200k,则删除-l结果可提高40%。
索林

Answers:


8

与以下选项相比仍然很慢,perl但值得比较的一个选项:

raku -ne '++$ andthen END .say' test.txt

l命令行选项是多余的。

$ 是匿名状态标量。

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

END类似perlEND。请注意,它返回Nil到,andthen但在这里并不重要,因为我们正在使用END的语句来产生副作用。

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

  • 编译器的启动开销。忽略正在使用的任何模块,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

where模块foo将文件I / O的默认编码切换为ASCII或可用编码中的任何一种。

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.