我们需要对任何可调用对象进行序列化
最近有人问到关于一些Python代码的问题,这段代码试图通过使用“序列化”的进程来实现分布式计算。听说这种功能以前是可以的,但出于安全原因,现在这个功能被禁用了。在第二次尝试通过网络传输一个函数对象时,实际上只传输了一个引用。如果我说错了请纠正我,但我认为这个问题和Python的延迟绑定没有关系。假设进程和线程对象不能被序列化,那么有没有办法传输一个可调用的对象呢?我们希望避免为每个任务传输压缩后的源代码,因为那样可能会让整个尝试变得毫无意义。为了便于移植,只能使用Python的核心库。
1 个回答
14
你可以把字节码打包起来,然后把其他函数的东西保存下来:
import marshal
import pickle
marshaled_bytecode = marshal.dumps(your_function.func_code)
# In this process, other function things are lost, so they have to be sent separated.
pickled_name = pickle.dumps(your_function.func_name)
pickled_arguments = pickle.dumps(your_function.func_defaults)
pickled_closure = pickle.dumps(your_function.func_closure)
# Send the marshaled bytecode and the other function things through a socket (they are byte strings).
send_through_a_socket((marshaled_bytecode, pickled_name, pickled_arguments, pickled_closure))
在另一个Python程序中:
import marshal
import pickle
import types
# Receive the marshaled bytecode and the other function things.
marshaled_bytecode, pickled_name, pickled_arguments, pickled_closure = receive_from_a_socket()
your_function = types.FunctionType(marshal.loads(marshaled_bytecode), globals(), pickle.loads(pickled_name), pickle.loads(pickled_arguments), pickle.loads(pickled_closure))
而且在函数内部引用的全局变量需要在接收函数的脚本中重新创建。
在Python 3中,使用的函数属性有 __code__
、__name__
、__defaults__
和 __closure__
。
请注意,send_through_a_socket
和 receive_from_a_socket
实际上并不存在,你需要用实际的代码来替换它们,以便通过套接字传输数据。