是否有一种直观的方法来循环多处理。连接对象直到达到EOF?

时间:2017-06-30 15:43:06

标签: python python-multiprocessing

我正在开发一种工具来抓取推文并对其进行处理,以便用户构建一个词频分析。由于需要处理大量数据,我将文字处理部分与推文抓取部分分开。

multiprocessing.Connectionrec, sen = multiprocessing.Pipe(False))提供了一个在流程之间传输数据的有用工具。但是,当发送端显式调用Connection.close()时,我找不到接收端何时到达EOF的实用程序。我试过了:

def yielder(conn):
    yield conn.recv()

但是在仅返回管道中的第一个项目之后,这会以某种方式停止。 我目前在while True循环中使用Try-Except语句绕过了这个问题:

try:
    status = rec.recv()
    ...process data...
except BrokenPipeError:
    break

我还可以看到这是通过发送一个特定的结束标记来完成的,让接收端在接收到它时终止进程。但这些都是非常反直觉和丑陋的方式,违反了Python的禅宗:

  

美丽胜过丑陋。

     

...

     

应该有一个 - 最好只有一个 - 显而易见的方法。

我错过了什么吗?是否有简单,优雅的方式,如c ++的

while getline(istreamobject, line)

执行我的任务?

1 个答案:

答案 0 :(得分:0)

您可以使用调用iter的第二种形式:iter(callable, sentinel) -> iterator将其转换为for循环。你仍然必须抓住异常。

try:
    for status in iter(conn.recv, None):
        ...
except BrokenPipeError:
    pass

如果不是关闭管道,而是向管道发送“eof”,您可以删除try/except并执行for status in iter(conn.recv, 'EOF message'),并在收到'EOF message'时(可以是任何内容) ),iter停止for循环。通常EOF消息是一个空字符串,因此通常会看到如下内容:

for line in iter(file.read, ''):
    ...

itertools recipes将此功能称为iter_except。这基本上是您之前使用yielder函数

所要做的
def iter_except(func, exception, first=None):
    """ Call a function repeatedly until an exception is raised.

    Converts a call-until-exception interface to an iterator interface.
    Like builtins.iter(func, sentinel) but uses an exception instead
    of a sentinel to end the loop.

    Examples:
        iter_except(functools.partial(heappop, h), IndexError)   # priority queue iterator
        iter_except(d.popitem, KeyError)                         # non-blocking dict iterator
        iter_except(d.popleft, IndexError)                       # non-blocking deque iterator
        iter_except(q.get_nowait, Queue.Empty)                   # loop over a producer Queue
        iter_except(s.pop, KeyError)                             # non-blocking set iterator

    """
    try:
        if first is not None:
            yield first()            # For database APIs needing an initial cast to db.first()
        while True:
            yield func()
    except exception:
        pass

所以,你也可以这样做:

for status in iter_except(conn.recv, BrokenPipeError):
    ...

或者只是修复yielder功能:

def yielder(conn):
    try:
        while True:
            yield conn.recv()
    except BrokenPipeError:
        pass

for status in yielder(conn):
    ...