假设我有一些Python代码,如下所示:
input = open("input.txt")
x = (process_line(line) for line in input)
y = (process_item(item) for item in x)
z = (generate_output_line(item) + "\n" for item in y)
output = open("output.txt", "w")
output.writelines(z)
此代码从输入文件中读取每一行,通过多个函数运行它,并将输出写入输出文件。现在我知道函数process_line
,process_item
和generate_output_line
永远不会相互干扰,让我们假设输入和输出文件是分开的磁盘,这样读写就不会互相干扰。
但Python可能不知道这些。我的理解是Python将读取一行,依次应用每个函数,并将结果写入输出,然后在将第一行发送到输出后仅读取的第二行,所以在第一行退出之前,第二行不会进入管道。我是否正确理解该程序将如何流动?如果这是它的工作方式,是否有任何简单的方法可以使多个行同时在管道中,以便程序可以并行读取,写入和处理每个步骤?
答案 0 :(得分:5)
您无法真正并行化读取或写入文件;这些将是你的瓶颈,最终。您是否确定这里的瓶颈是CPU,而不是I / O?
由于您的处理不包含任何依赖项(根据您),因此使用Python's multiprocessing.Pool class非常简单。
有几种方法可以写这个,但更容易w.r.t.调试是为了找到独立的关键路径(代码的最慢部分),我们将使它们并行运行。我们假设它是process_item。
......实际上就是这样。代码:
import multiprocessing.Pool
p = multiprocessing.Pool() # use all available CPUs
input = open("input.txt")
x = (process_line(line) for line in input)
y = p.imap(process_item, x)
z = (generate_output_line(item) + "\n" for item in y)
output = open("output.txt", "w")
output.writelines(z)
我没有测试过,但这是基本的想法。 Pool的imap方法确保以正确的顺序返回结果。
答案 1 :(得分:1)
有没有什么简单的方法可以让多行同时在管道中
我编写了一个库来做到这一点:https://github.com/michalc/threaded-buffered-pipeline,它在单独的线程中迭代每个可迭代对象。
那是什么
input = open("input.txt")
x = (process_line(line) for line in input)
y = (process_item(item) for item in x)
z = (generate_output_line(item) + "\n" for item in y)
output = open("output.txt", "w")
output.writelines(z)
变成
from threaded_buffered_pipeline import buffered_pipeline
input = open("input.txt")
buffer_iterable = buffered_pipeline()
x = buffer_iterable((process_line(line) for line in input))
y = buffer_iterable((process_item(item) for item in x))
z = buffer_iterable((generate_output_line(item) + "\n" for item in y))
output = open("output.txt", "w")
output.writelines(z)
这增加了多少实际并行度取决于每个迭代中实际发生的事情,以及您拥有多少 CPU 内核/它们有多忙。
经典的例子是 Python GIL:如果每个步骤都占用大量 CPU,并且只使用 Python,那么不会增加太多并行性,这可能不会比串行版本快。另一方面,如果每个都是网络 IO 繁重的,那么我认为它可能会更快。