假设我具有以下具有多个昂贵属性的对象:
class Object:
def __init__(self, num):
self.num = num
@property
def expensive_property(self):
return expensive_calculation
@property
def expensive_property1(self):
return expensive_calculation
@property
def expensive_property2(self):
return expensive_calculation
注意:昂贵属性的数量可能会随着时间增加。
给定一个Objects
列表,我如何为列表中的所有对象计算每个线程的每个昂贵属性。我很难弄清楚如何安排泳池。
这是我想要实现的目标:
from multithreading.dummy import Pool
from multithreading.dummy import Queue
object_list = [Object(i) for i in range(20)]
properties = [expensive_property2, expensive_propert5, expensive_property9, expensive_property3]
def get(obj, expensive_property):
return [getattr(expensive_property, o) for o in obj]
tasks = Queue()
for p in properties :
tasks.put((get, o, p))
results = []
with Pool(len(properties )) as pool:
while True:
task = tasks.get()
if task is None:
break
func, *args = task
result = pool.apply_async(func, args)
results.append(result)
答案 0 :(得分:1)
这有点疯狂,因为apply_async
有一个internal queue可以在池中分配任务。我可以想象有理由在可观察性或反压力问题上再排队。您的示例是您的完整程序吗?还是您在其他进程/线程中排队工作?
如果您的计算受CPU限制,一个选择可能是删除队列以使事情变得简单一些:
def wait_all(async_results, timeout_seconds_per_task=1):
for r in async_results:
r.get(timeout_seconds)
wait_all(
[pool.apply_async(get, (o, p)) for p in properties],
timeout_seconds_per_task=1,
)
就像上面的示例一样,这使您可以在可用的CPU上分配计算(池甚至默认为cpus on your machine的数量)。如果您的工作受IO约束(建议您入睡),则流程的收益可能会减少。
您必须进行基准测试,但是对于IO绑定,您可以使用相同的模式https://stackoverflow.com/a/3034000/594589
创建线程池其他选项可能是将非阻塞IO与事件循环(例如gevent或asyncio)一起使用。两者都将允许您对相同的基于池的模式进行建模!