我有一些复杂的类 A 计算数据(大型矩阵计算),同时消耗来自 B 类的输入数据。
A 本身使用多个核心。但是,当 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的多处理模块没有多少经验,所以我构建了一个简单/简单的方法。但是,它对我来说看起来有些“hacky”。
让一个类 B 同时从磁盘加载数据并通过某个队列提供数据是一个更好的解决方案,而主线程运行大量计算并不时从队列中消耗数据?
答案 0 :(得分:1)
虽然您的解决方案完全没问题,特别是对于“小型”项目,但它具有与类animate()
紧密耦合的线程的缺点。因此,如果您(例如)由于某种原因想要以非 - 线程的方式使用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()
更灵活,更好地分离依赖关系并且更容易测试。它还通过显式关于线程创建使代码更具可读性,与在类创建时隐式发生相比。