我有一些复杂的类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/