如何在Node.js中实现不加载全文件的Unix paste命令?
用Node.js实现Unix paste命令的高效方案探讨
基础的Unix paste命令可通过如下Python代码实现(该示例仅支持两个文件,原版Unix paste支持多文件):
def paste(fn1, fn2): with open(fn1) as f1: with open(fn2) as f2: for l1 in f1: l2 = f2.readline() if l2 != None: print(l1[:-1] + "\t" + l2[:-1]) else: print(l1[:-1]) for l2 in f2: print("\t" + l2[:-1]) import sys if __name__ == "__main__": if len(sys.argv) >= 3: paste(sys.argv[1], sys.argv[2])
任务要求
本次任务要求用Node.js实现相同功能,重点说明:由于输入文件可能极大,实现需逐行读取文件,而非将整个文件加载到内存中,且需仅使用Node.js内置功能,不依赖外部包。
Node.js实现的难点
如Python示例所示,使用同步I/O实现Unix paste较为简单,但Node.js并未提供用于逐行读取的同步I/O接口。同时,虽有方法可异步逐行读取单个文件,但同时读取两个文件难度较大,因为两个流无法同步。
目前能想到的唯一解决方案是使用基础read API实现同步逐行读取。有评论指出,npm的n-readlines包通过此方法实现,代码量超100行。由于n-readlines需检查每个字节以找到行尾,怀疑其效率低下,因此进行了微基准测试,结果如下表所示。仅针对逐行读取任务(非本次paste任务),n-readlines的速度是Node.js Readline实现的1/3,比Python、Perl或mawk的内置逐行读取慢一个数量级。
微基准测试结果
| 编程语言 | 运行时 | 版本 | 耗时(秒) | 用户态耗时(秒) | 内核态耗时(秒) | 代码 |
|---|---|---|---|---|---|---|
| JavaScript | node | 21.5.0 | 6.30 | 5.33 | 0.90 | lc-node.js |
| JavaScript | node | 21.5.0 | 22.34 | 20.41 | 2.24 | lc-n-readlines.js |
| JavaScript | bun | 1.0.20 | 4.91 | 5.30 | 1.47 | lc-node.js |
| JavaScript | bun | 1.0.20 | 21.16 | 19.22 | 3.37 | lc-n-readlines.js |
| JavaScript | k8 | 1.0 | 1.49 | 1.06 | 0.37 | lc-k8.js |
| C | clang | 15.0.0 | 0.71 | 0.35 | 0.35 | lc-c.c |
| python | python | 3.11.17 | 3.48 | 2.85 | 0.62 | lc-python.py |
| perl | perl | 5.34.3 | 1.70 | 1.13 | 0.57 | lc-perl.pl |
| awk | mawk | 1.3.4 | 2.08 | 1.27 | 0.80 | lc-awk.awk |
| awk | apple awk | ? | 90.06 | 87.90 | 1.12 | lc-awk.awk |
核心问题
实现Unix paste的恰当方式是什么?n-readlines使用同步API,那么优秀的异步解决方案是否会更简洁高效?
内容的提问来源于stack exchange,提问作者user172818
相关产品推荐
相关产品推荐

