【问题标题】:Embarassingly parallel tasks with IPython Parallel (or other package) depending on unpickable objects使用 Python Parallel(或其他包)进行令人尴尬的并行任务,具体取决于不可拾取的对象
【发布时间】:2023-12-15 18:56:01
【问题描述】:

我经常遇到一些问题,我想在一组很多很多对象上快速做一些简单的事情。我的自然选择是使用 IPython Parallel,因为它很简单,但我经常不得不处理不可拾取的对象。在尝试了几个小时之后,我通常会选择让自己在一夜之间在一台计算机上运行任务,或者做一些愚蠢的事情,比如半手动地把东西分成多个 Python 脚本来运行。

举一个具体的例子,假设我想删除给定 S3 存储桶中的所有键。

我通常不假思索地做的是:

import boto
from IPython.parallel import Client

connection = boto.connect_s3(awskey, awssec)
bucket = connection.get_bucket('mybucket')

client = Client()
loadbalancer = c.load_balanced_view()

keyList = list(bucket.list())
loadbalancer.map(lambda key: key.delete(), keyList)

问题是boto 中的Key 对象不可拾取(*)。这对我来说经常发生在不同的环境中。这也是我尝试过的多处理、execnet 和所有其他框架和库的问题(原因很明显:它们都使用相同的pickler 来序列化对象)。

你们也有这些问题吗?有没有办法可以序列化这些更复杂的对象?我是否必须为这个特定的对象编写自己的pickler?如果我这样做了,我如何告诉 IPython Parallel 使用它?我如何写一个pickler?

谢谢!


(*) 我知道我可以简单地列出键名并执行以下操作:

loadbalancer.map(lambda keyname: getKey(keyname).delete())

并在 IPython 集群的每个引擎中定义 getKey 函数。这只是我经常发现的更普遍问题的一个特定实例。也许这是一个不好的例子,因为它可以通过另一种方式轻松解决。

【问题讨论】:

  • 我敢肯定,这些任务已经够尴尬了,不用你在 SO 上取笑它们!

标签: python parallel-processing ipython ipython-parallel


【解决方案1】:

IPython 有一个use_dill 选项,如果您安装了dill 序列化程序,则可以序列化大多数“不可选择”的对象。

How can I use dill instead of pickle with load_balanced_view

【讨论】:

    【解决方案2】:

    IPython 确实将人们聚集在一起 ;)。因此,据我所知,酸洗对象的问题在于它们的方法。所以也许不是使用key 的方法来删除它,你可以编写一个函数来获取它并删除它。也许首先获取dict 的列表以及每个键的相关信息,然后调用一个函数delete_key( dict ),因为我不知道如何处理 s3 键,所以我留给你写。

    这行得通吗?


    或者,这可能是有效的:只需调用类的方法,而不是调用实例的方法,并将实例作为参数。因此,您可以使用lambda key : Key.delete(key) 而不是lambda key : key.delete()。当然,您必须将类推送到节点,但这应该不是问题。一个最小的例子:

     class stuff(object):
           def __init__(self,a=1):
                self.list = []
           def append(self, a):
                self.list.append(a)
    
      import IPython.parallel as p
      c = p.Client()
      dview = c[:]
    
      li = map( stuff, [[]]*10 ) # creates 10 stuff instances
    
      dview.map( lambda x : x.append(1), li ) # should append 1 to all lists, but fails
    
      dview.push({'stuff':stuff}) # push the class to the engines
      dview.map( lambda x : stuff.append(x,1), li ) # this works.
    

    【讨论】: