在IPython Parallel中处理无法序列化的尴尬并行任务(或其他包)
我经常遇到这样的问题:我想快速对一大堆对象做一些简单的操作。我的自然选择是使用 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 以及我尝试过的其他框架和库时遇到的问题(原因很明显:它们都使用同样的序列化工具来处理对象)。
你们也有这样的烦恼吗?有没有办法让我序列化这些更复杂的对象?我需要为这些特定的对象写一个自己的序列化工具吗?如果需要,我该如何告诉 IPython Parallel 使用它?我该如何编写一个序列化工具?
谢谢!
(*) 我知道我可以简单地列出键的名称,然后这样做:
loadbalancer.map(lambda keyname: getKey(keyname).delete())
并在 IPython 集群的每个引擎中定义 getKey
函数。这只是我经常遇到的一个更普遍问题的一个特例。也许这个例子不太好,因为它可以用其他方法轻松解决。
2 个回答
IPython真是让大家聚在一起啊;)。根据我了解到的情况,问题出在对象的方法上。也就是说,或许你可以不直接用key
的方法来删除它,而是写一个函数,传入这个键,然后删除它。你可以先获取一个包含每个键相关信息的dict
列表,然后再调用一个函数delete_key( dict )
,这个函数的具体实现就留给你自己去写,因为我对处理s3键没什么头绪。
这样行得通吗?
另外一种可能是这样做:与其调用实例的方法,不如用实例作为参数来调用类的方法。所以,不用lambda key : key.delete()
,而是用lambda key : Key.delete(key)
。当然,你得把类推送到节点上,但这应该不成问题。下面是一个简单的例子:
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.
IPython
有一个 use_dill
选项,如果你安装了 dill
这个工具,你就可以把大部分“无法被序列化”的对象进行序列化。