加入并发Python输出

8
我正在使用类似这样的东西:
find folder/ | xargs -n1 -P10 ./logger.py > collab

我正在处理输出文件并输出重新格式化的行。因此,collab应该看起来像这样:

{'filename' : 'file1', 'size' : 1000}
{'filename' : 'file1', 'size' : 1000}
{'filename' : 'file1', 'size' : 1000}
{'filename' : 'file1', 'size' : 1000}

有时候,代码行会混乱:

{'filename' : 'file1', 'size' : 1000}
{'file
{'filename' : 'file1', 'size' : 1000}
name' : 'file1', 'size' : 1000}
{'filename' : 'file1', 'size' : 1000}

我该如何预防/纠正这个问题?

你的logger.py是多线程的吗? - aioobe
1
@aioobe:xargs -n1 -P10 运行十个并发进程(logger.py 的)。请参阅 xargs - Josh K
1
哦,对了,我误读了 man-page 并将其与“-p”混淆了。这是一个好问题! - aioobe
logger.py 中的输出是如何完成的? - Piotr Findeisen
@Josh,你尝试过在写入后添加flush或使用非缓冲文件对象吗?(顺便说一下,这是Glenn在下面建议的) - Piotr Findeisen
3个回答

2
一般情况下,如果不深入使用多进程锁定,就很难保证这种情况不会发生。然而,通常您可以大大减少问题的出现。
最常见的原因是Python或libc内部的I/O缓冲。例如,它可能会缓冲16k的输出,然后一次性写入整个块。您可以通过在写入后刷新stdout来减少这种情况,但这很麻烦。理论上,您应该能够向Python传递 -u 来禁用stdout缓冲,但当我尝试时它并没有起作用。有一个更通用的解决方案,请参见Sebastjan对Disable output buffering的回答(尽管可能有更直接的方法来禁用输出缓冲)。
第二个问题是底层写操作并不总是原子的。特别地,对于管道的写操作只有在一定大小范围内(PIPE_BUF, 通常为512字节)才是原子的;超过该大小则不能保证。这仅严格适用于管道(非文件),但同样的一般问题也适用:较小的写操作更有可能以原子方式发生。请参见http://www.opengroup.org/onlinepubs/000095399/functions/write.html

1

复杂而技术上正确的解决方案是实现写入互斥锁,但我认为这不是最优解。

而且这样做也不好玩。那么,从xargs中传输输出如何(这样你就可以得到坚实的输出块,而不是被打断的输出流),然后以某种方式组合这些块呢?


1
问题在于xargs的输出是混合在一起的。GNU Parallel就是为了解决这个问题而设计的。默认情况下,它保证输出不会混合在一起。因此,您可以简单地执行以下操作:
find folder/ | parallel ./logger.py > collab

这将在每个 CPU 上运行一个 logger.py。如果您想要 10 个:

find folder/ | parallel -P10 ./logger.py > collab

观看介绍视频以了解有关GNU Parallel的更多信息http://www.youtube.com/watch?v=OpaiGYxkSuQ

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接