我有一些复杂的类A,该类在消费类B的输入数据的同时计算数据(大型矩阵计算)。

一个本身使用多个核心。但是,当A需要下一个数据块时,由于B在同一主线程中运行,因此它会等待相当长的时间。

由于A主要使用GPU进行计算,因此我希望B同时在CPU上收集数据。

我最新的方法是:

# every time *A* needs data
def some_computation_method(self):
    data = B.get_data()
    # start computations with data

...而B看起来大致像这样:
class B(object):

    def __init__(self, ...):
        ...
        self._queue = multiprocessing.Queue(10)
        loader = multiprocessing.Process(target=self._concurrent_loader)

    def _concurrent_loader(self):
        while True:
            if not self._queue.full():
                # here: data loading from disk and pre-processing
                # that requires access to instance variables
                # like self.path, self.batch_size, ...
                self._queue.put(data_chunk)
            else:
                # don't eat CPU time if A is too busy to consume
                # the queue at the moment
                time.sleep(1)

    def get_data(self):
        return self._queue.get()

可以将此方法视为“pythonic”解决方案吗?

由于我对Python的多处理模块没有太多的经验,所以我建立了一种简单/简单的方法。但是,在我看来,这有点“骇客”。

有什么更好的解决方案,让B类同时从磁盘加载数据并通过某个队列提供数据,而主线程则运行大量计算并时不时地消耗队列中的数据?

最佳答案

虽然您的解决方案完全可以,尤其是对于“小型”项目,但它的缺点是线程与B类紧密结合。因此,如果您(例如)出于某种原因想要以非线程方式使用B,那么您就不走运了。

我个人将以线程安全的方式编写该类,然后使用外部线程进行调用:

class B(object):
    def __init__(self):
        self._queue = multiprocessing.Queue(10)

    ...

if __name__ == '__main__':
    b = B()

    loader = multiprocessing.Process(target=b._concurrent_loader)
    loader.start()

这使B更加灵活,更好地分离了依赖关系,并且更易于测试。与隐式发生在类创建上相比,通过隐式地在线程创建上使用显式,还可以使代码更具可读性。

关于Python 3 multiprocessing.Process在类内部?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/45296526/

10-12 23:10