为什么Linux可以在多处理中接受套接字?

时间:2016-12-05 08:28:31

标签: python linux sockets python-multiprocessing

此代码在Linux上运行良好,但在Windows下失败(预期)。我知道多处理模块使用fork()来生成一个新进程,因此父进程拥有的文件描述符(即打开的套接字)由子进程继承。但是,我的理解是,您可以通过多处理发送的唯一类型的数据需要是可选择的。在Windows和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对象,一个明显不可拾取的对象,可以通过多处理传递?是不是像Windows那样使用泡菜?

2 个答案:

答案 0 :(得分:6)

在unix平台上,套接字和其他文件描述符可以使用unix域(AF_UNIX)套接字发送到不同的进程,因此套接字可以在多处理的上下文中进行腌制

多处理模块使用特殊的pickler实例而不是常规的pickler ForkingPickler来pickle套接字和文件描述符,然后可以在不同的进程中进行unpickled。这是唯一可行的,因为已知pickle实例将被打开的地方,挑选一个套接字或文件描述符并在机器边界之间发送它是没有意义的。

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

答案 1 :(得分:1)

我认为问题是public class Model{ private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } } 对Windows和非Windows系统使用不同的pickler。在Windows上,没有真正的multiprocessing,并且完成的酸洗相当于跨机器边界(即分布式计算)进行酸洗。在非Windows系统上,可以跨进程边界共享对象(如文件描述符)。因此,Windows系统(fork())上的酸洗更加有限。

pickle包确实使用multiprocessing将一些对象类型注册到copy_reg,其中一种类型为pickle。但是,由于Windows pickler较弱,Windows上使用的socket对象的序列化更加有限。

在相关说明中,如果您确实希望在Windows上发送socket socket对象,则可以......您只需使用multiprocessingmultiprocessdill使用{{ 1}}而不是pickledill有一个更好的序列化程序,可以在任何操作系统上挑选socket个对象,因此在任何一种情况下都可以发送带有socket的{​​{1}}对象。

multiprocess具有dill功能;基本上copy - 这对于检查对象很有用,可以序列化。 loads(dumps(object))也有dill,其执行check但限制性更强的&#34; Windows&#34;风格叉式操作。这允许非Windows系统上的用户在Windows系统上或跨分布式资源模拟copy

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> >>> 在Windows上使用的pickler与在非Windows系统上使用的pickler不同引起的。但是,通过使用更好的序列化器(如multiprocessing中所使用的),可以(并且很容易)在任何操作系统上工作。