繁体   English   中英

Python线程stdin / stdout

[英]Python Threading stdin/stdout

我有一个包含大量数据的文件。 每行都是一条记录。 我试图对整个文件做一些ETL工作。 现在我正在使用标准输入逐行读取数据。 关于这一点很酷的是你的脚本可以非常灵活地与其他脚本和shell命令集成。 我将结果写入标准输出。 例如。

$ cat input_file
line1 
line2
line3
line4
...

我当前的python代码如下所示 - parse.py

import sys
for line in sys.stdin:
    result = ETL(line)    # ETL is some self defined function which takes a while to execute.
    print result

下面的代码是它现在的工作方式:

cat input_file | python parse.py > output_file

我查看了Python的Threading模块,我想知道如果我使用该模块,性能是否会得到显着改善。

问题1: 我应该如何规划每个线程的配额,为什么?

...
counter = 0
buffer = []
for line in sys.stdin:
    buffer.append(line)
    if counter % 5 == 0:   # maybe assign 5 rows to each thread? if not, is there a rule of thumb to determine
        counter = 0
        thread = parser(buffer)
        buffer = []
        thread.start() 

问题2: 多线程可能会同时将结果打印回stdout,如何组织它们并避免下面的情况?

import threading
import time

class parser(threading.Thread):
    def __init__ (self, data_input):
        threading.Thread.__init__(self)
        self.data_input = data_input

    def run(self):
        for elem in self.data_input:
            time.sleep(3)
            print elem + 'Finished'

work = ['a', 'b', 'c', 'd', 'e', 'f']

thread1 = parser(['a', 'b'])  
thread2 = parser(['c', 'd'])
thread3 = parser(['e', 'f'])

thread1.start()
thread2.start()
thread3.start()   

输出真的很难看,其中一行包含两个线程的输出。

aFinished
cFinishedeFinished

bFinished
fFinished
dFinished

首先提出第二个问题,这就是互斥体的用途。 您可以通过使用锁来协调解析器之间来获得所需的更清晰的输出,并确保在给定的时间段内只有一个线程可以访问输出流:

class parser(threading.Thread):
    output_lock = threading.Lock()

    def __init__ (self, data_input):
        threading.Thread.__init__(self)
        self.data_input = data_input

    def run(self):
        for elem in self.data_input:
            time.sleep(3)
            with self.output_lock:
                print elem + 'Finished'

关于您的第一个问题,请注意,多线程可能无法为您的特定工作负载带来任何好处。 这在很大程度上取决于您对每个输入行(您的ETL函数)所做的工作是主要是CPU绑定还是IO绑定。 如果是前者(我怀疑可能),由于全局解释器锁定 ,线程将无济于事。 在这种情况下,您可能希望使用multiprocessing模块在多个进程之间分配工作而不是多个线程。

但是您可以通过更容易实现的工作流程获得相同的结果:将输入文件拆分为n (使用例如split命令); 在每个子文件上分别调用extract-and-transform脚本; 然后连接生成的输出文件。

一个挑剔:“使用标准输入逐行读取数据,因为它不会将整个文件加载到内存中”涉及一个误解。 您可以在Python中逐行读取文件,例如,将sys.stdin替换为以下sys.stdin中的文件对象:

for line in sys.stdin:

另请参见文件对象的readline()方法,并注意read()可以将要读取的最大字节数作为参数。

无论线程是否有用,您都高度依赖于您的情况。 特别是,如果您的ETL()函数涉及大量磁盘访问,那么线程可能会给您带来非常显着的速度提升。

在回答你的第一个问题时,我总是发现它只是取决于你。 在确定理想的线程数时,有许多因素在起作用,其中许多因素与程序有关。 例如,如果您正在进行大量磁盘访问(这非常慢),那么您将需要更多线程在等待磁盘访问时利用停机时间。 但是,如果该程序受CPU限制,那么大量的线程可能不会非常有用。 因此,尽管可以分析所有因素以得出理想数量的线程,但通常可以更快地进行初始猜测,然后从那里进行调整。

更具体地说,为每个线程分配一定数量的行可能不是分配工作的最佳方式。 例如,考虑一行是否需要特别长的时间来处理。 最好是一个线程可以在那一行上工作,而其他线程可以在此期间再做几行。 处理此问题的最佳方法是使用队列。 如果将每一行推入队列,则每个线程都可以从队列中拉出一行,处理它,然后重复,直到队列为空。 通过这种方式,工作得到分配,使得没有线程没有工作要做(当然,直到最后)。

现在,第二个问题。 你肯定从多个线程写入stdout并不是一个理想的解决方案。 理想情况下,您可以安排一些事情,以便只在一个地方写入stdout。 一个很好的方法是使用队列。 如果你让每个线程将其输出写入共享队列,那么你可以产生一个额外的线程,其唯一的任务是将项目拉出该队列并将它们打印到stdout。 通过将打印限制为仅一个线程,您将避免多个线程尝试一次打印时固有的问题。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM