unix管道上的懒惰python

时间:2017-02-27 18:03:51

标签: python iterator pipe generator

我有4GB big_file.txt,所以如果我尝试:

cat big_file.txt |
python3 -c "print( open('/dev/stdin').read() )" |
less

我的RAM爆炸了,我死了。但如果我:

cat big_file.txt |
python3 -c "
for line in open('/dev/stdin'):
  print(line)
" |
less

RAM静止不动,我可以向下滚动,通过less按需读取文件,甚至通过python。我甚至可以在打印前处理这条线,一切正常。

所以我想我可以:

seq 1 100 |
python3 -c "
fib = lambda n: n if n < 2 else fib(n - 1) + fib(n - 2)
for line in open('/dev/stdin'):
  print( fib( int(line) ) )
" |
less

但这会打击CPU,我又死了。 更改printsys.stdout.write的{​​{1}}可以至少在sys.stdout.flush中查看结果,但即使我不向下滚动,CPU也会保持100% ,显然执行我没有要求的线。

起初我认为这是一个“阅读块”的事情,好像有最少量的数据需要通过管道输送,所以我试过了:

less

(请注意,此seq -10000 100 | python3 -c " import sys fib = lambda n: n if n < 2 else fib(n - 1) + fib(n - 2) for line in open('/dev/stdin', 'r'): sys.stdout.write( str( fib( int(line) ) ) + '\n' ) sys.stdout.flush() " | less 只是回应任何fib

但仍然没有运气。 我也试过了 n < 2

发生了什么事?为什么在seq -10000 100 > numbers.txt && cat numbers.txt | python3 -c blablabla示例中我可以根据需要进行管道,而big_file.txt我不能管道?

1 个答案:

答案 0 :(得分:1)

less执行的预读量远大于CPU优化的测试。尝试:

seq 1000000 | tee test.out | less

并查看test.out的大小。在我的系统上,它是80KB。

fib结果的80KB预读将确实会耗尽你的CPU。

如果你想了解没有 less的管道缓冲,你可以做类似的事情:

seq 1000000 | tee test.out | { while read; do read </dev/tty; done; }

...它往往会有点小(在我的系统上,72KB),但仍然在大多数现代的unixlikes非常重要。