如何使用getattr多线程,每个属性一个线程?

时间:2018-12-10 23:38:22

标签: python-3.x multithreading threadpool getattr

假设我具有以下具有多个昂贵属性的对象:

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)

1 个答案:

答案 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)一起使用。两者都将允许您对相同的基于池的模式进行建模!