2016-12-05 55 views
10

此代码在Linux上正常工作,但在Windows下(预期)失败。我知道多处理模块使用fork()产生一个新进程,父进程拥有的文件描述符(即打开的套接字)因此被子进程继承。但是,我的理解是,您可以通过多处理发送的唯一类型的数据需要被选中。在Windows和Linux上,套接字对象不可选。Linux为什么可以在多处理器中接受套接字?

from socket import socket, AF_INET, SOCK_STREAM 
import multiprocessing as mp 
import pickle 

sock = socket(AF_INET, SOCK_STREAM) 
sock.connect(("www.python.org", 80)) 
sock.sendall(b"GET/HTTP/1.1\r\nHost: www.python.org\r\n\r\n") 

try: 
    pickle.dumps(sock) 
except TypeError: 
    print("sock is not pickleable") 

def foo(obj): 
    print("Received: {}".format(type(obj))) 
    data, done = [], False 
    while not done: 
     tmp = obj.recv(1024) 
     done = len(tmp) < 1024 
     data.append(tmp) 
    data = b"".join(data) 
    print(data.decode()) 


proc = mp.Process(target=foo, args=(sock,)) 
proc.start() 
proc.join() 

我的问题是,为什么可以在socket对象,demonstrably非与pickle对象,具有多重传递吗?它不像Windows那样使用泡菜吗?

+4

文件描述符不是“发送”的,它们就在那里。 –

+0

你是什么意思?我可能(而且必须部分)错误,但我认为“参数”参数中的任何内容都需要可以选择。这不是这种情况吗? – Goodies

+1

参数不被pickle,它们只传递给子进程中的函数。只有*进程之间传输的对象需要进行酸洗。 –

回答

6

在UNIX平台插座等文件描述符可以传送到使用UNIX域(AF_UNIX)插孔的不同的过程,所以插座可以在多的情况下进行酸洗。

多处理模块使用特殊的pickler实例而不是常规的pickler,ForkingPickler来腌制套接字和文件描述符,然后这些描述符可以在不同的进程中取消选择。只有这样才能做到这一点,因为已知pick pick实例的位置将被取消,因此pickle套接字或文件描述符并在机器边界之间发送它是没有意义的。

对于Windows,打开文件句柄有similar mechanisms

1

我认为问题在于multiprocessing对Windows和非Windows系统使用不同的pickler。在Windows上,没有真正的fork(),所完成的酸洗等同于跨机器边界酸洗(即分布式计算)。在非Windows系统上,可以跨进程边界共享对象(如文件描述符)。因此,在Windows系统(pickle)上酸洗更加有限。

multiprocessing程序包确实使用copy_reg将几个对象类型注册为pickle,其中一种类型为socket。但是,由于Windows pickler较弱,所以在Windows上使用的socket对象的序列化更受限制。

与此相关的,如果你想在Windows发送socket对象与multiprocessing,你可以...你只需要使用包multiprocess,它采用dill而不是pickledill有一个更好的序列化器,可以在任何操作系统上腌制socket对象,因此在任何情况下都会发送socket对象和multiprocess作品。

dill具有功能copy;本质上是loads(dumps(object)) - 这对于检查可以序列化的对象很有用。 dill也有check,它执行copy但具有更严格的“Windows”风格叉式操作。这允许非Windows系统上的用户在Windows系统上或跨分布式资源模拟copy

>>> import dill 
>>> import socket 
>>> s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
>>> s.connect(('www.python.org', 80)) 
>>> s.sendall(b'GET/HTTP/1.1\rnHost: www.python.org\r\n\r\n') 
>>> 
>>> dill.copy(s) 
<socket._socketobject object at 0x10e55b9f0> 
>>> dill.check(s) 
<socket._socketobject object at 0x1059628a0> 
>>> 

总之,所不同的是由multiprocessing使用在Windows比它使用在非Windows系统中的pickler不同的pickler引起的。但是,通过使用更好的串行器(如在multiprocess中使用的),可以(并且容易)在任何OS上工作。

+1

完全披露:我是'multiprocess'和'dill'的作者。 –

+0

非常有趣的模块,莳萝! – Goodies