为什么我的上下文管理器__exit__函数在计算完成之前运行?

时间:2017-04-05 23:20:07

标签: python python-multiprocessing contextmanager

我的自定义上下文管理器的退出功能似乎在计算完成之前运行。我的上下文管理器旨在简化编写并发/并行代码。这是我的上下文管理器代码:

import time
from multiprocessing.dummy import Pool, cpu_count

class managed_pool:
    '''Simple context manager for multiprocessing.dummy.Pool'''
    def __init__(self, msg):
        self.msg = msg
    def __enter__(self):
        cores = cpu_count()
        print 'start concurrent ({0} cores): {1}'.format(cores, self.msg)
        self.start = time.time()
        self.pool = Pool(cores)
        return self.pool
    def __exit__(self, type_, value, traceback):
        print 'end concurrent:', self.msg
        print 'time:', time.time() - self.start
        self.pool.close()
        self.pool.join()

我已经使用multiprocessing.Pool而不是multiprocessing.dummy.Pool尝试过此脚本,而且似乎一直都会失败。

以下是使用上下文管理器的示例:

def read_engine_files(f):
    engine_input = engineInput()
    with open(f, 'rb') as f:
        engine_input.parse_from_string(f.read())
    return engine_input

with managed_pool('load input files') as pool:
    data = pool.map(read_engine_files, files)

因此,在read_engine_files内,我打印文件的名称。您将在__exit__函数中注意到,在计算完成时我也会打印出来,以及花了多长时间。但是在查看stdout时,__exit__消息在计算完成之前出现。比如,计算完成前几分钟。但htop表示我的所有内核仍在使用中。这是输出的一个例子

start concurrent (4 cores): load engine input files
file1.pbin
file2.pbin
...
file16.pbin
end concurrent: load engine input files
time: 246.43829298
file17.pbin
...
file45.pbin

为什么__exit__被如此早地调用?

2 个答案:

答案 0 :(得分:1)

您确定只是致电pool.map()吗?这应该阻止,直到所有项目都已映射。

如果您正在调用Pool的异步方法之一,那么您应该可以通过更改__exit__()中的内容顺序来解决问题。在完成摘要之前,只需加入游泳池。

def __exit__(self, type_, value, traceback):
    self.pool.close()
    self.pool.join()
    print 'end concurrent:', self.msg
    print 'time:', time.time() - self.start

答案 1 :(得分:0)

最可能的解释是发生了异常。上面的代码示例未解析type语句的valuetraceback__exit__自变量。因此,发生了一个异常(并且没有更早捕获),该异常被交给了退出语句,而退出语句又对该异常没有反应。进程(或其中一些)继续运行。