RuntimeError: received 0 items of ancdata when sharing sockets between processes
RuntimeError: received 0 items of ancdata when sharing sockets between processes
这是我能想象的没有错误处理、正常退出等的最少代码
#!/usr/bin/env python3.5
import multiprocessing, socket, traceback
from multiprocessing import reduction
def loop(pipe):
while True:
try:
c = socket.fromfd(reduction.recv_handle(pipe), socket.AF_INET, socket.SOCK_STREAM)
c.sendall('HTTP/1.1 200 OK\r\nContent-Length: 6\r\nContent-Type: text/plain\r\n\r\nhello\n'.encode())
c.shutdown(socket.SHUT_WR)
c.close()
except: print(traceback.format_exc())
if __name__ == '__main__':
pipe_recv, pipe_send = multiprocessing.Pipe()
proc = multiprocessing.Process(target=loop, args=(pipe_recv,))
proc.start()
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(('localhost', 9000))
s.listen()
while True:
conn, addr = s.accept()
reduction.send_handle(pipe_send, conn.fileno(), proc.pid)
我可以curl
它:
curl -v http://localhost:9000/
* Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 9000 (#0)
> GET / HTTP/1.1
> Host: localhost:9000
> User-Agent: curl/7.47.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Content-Length: 6
< Content-Type: text/plain
<
hello
* Connection #0 to host localhost left intact
当我有一个或几个循环的 curl-s 时,它工作得很好,但是如果我创建很多 'client' 或只是使用 apache 基准测试,例如,脚本崩溃:
Traceback (most recent call last):
File "/tmp/this-is-my-script", line 8, in loop
c = socket.fromfd(reduction.recv_handle(pipe), socket.AF_INET, socket.SOCK_STREAM)
File "/usr/lib/python3.5/multiprocessing/reduction.py", line 181, in recv_handle
return recvfds(s, 1)[0]
File "/usr/lib/python3.5/multiprocessing/reduction.py", line 160, in recvfds
len(ancdata))
RuntimeError: received 0 items of ancdata
我花了很多时间试图理解这一点,但没有成功。所以我放弃了问这个问题。 reduction
模块甚至没有记录在 3.5
中。这是否意味着我不应该使用它?
如果没有 - 我没有看到任何其他在进程之间共享套接字的可能性,有吗?
如果是 - 我想念什么?
终于!
- 无需调用
socket.fromfd()
。我的代码基于 this gist,不确定 python2,但在 3.5 中它肯定会导致不需要的套接字重复创建,而它又保留在 TIME_WAIT 中,如果调用 socket.socket()
直接。
fromfd() 来源:
def fromfd(fd, family, type, proto=0):
nfd = dup(fd)
return socket(family, type, proto, nfd)
在发送方传输后必须关闭套接字
此外,无条件关闭子进程中的套接字导致 apache 基准测试挂起。完全没有 close()
就可以正常工作。
所以最终版本如下。它实际上不是多进程的,所以它会通过 -c
参数的 apache 基准测试失败。但这超出了问题的范围。
#!/usr/bin/env python3.5
import multiprocessing, socket, traceback
from multiprocessing import reduction
def loop(pipe_recv):
while True:
try:
conn = socket.socket(fileno=reduction.recv_handle(pipe_recv))
conn.sendall('HTTP/1.0 200 OK\r\nContent-Length: 6\r\nContent-Type: text/plain\r\n\r\nhello\n'.encode())
conn.shutdown(socket.SHUT_WR)
except: print(traceback.format_exc())
if __name__ == '__main__':
pipe_recv, pipe_send = multiprocessing.Pipe()
proc = multiprocessing.Process(target=loop, args=(pipe_recv,))
proc.start()
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(('localhost', 9000))
s.listen(100)
while True:
conn, addr = s.accept()
reduction.send_handle(pipe_send, conn.fileno(), proc.pid)
conn.close()
这是我能想象的没有错误处理、正常退出等的最少代码
#!/usr/bin/env python3.5
import multiprocessing, socket, traceback
from multiprocessing import reduction
def loop(pipe):
while True:
try:
c = socket.fromfd(reduction.recv_handle(pipe), socket.AF_INET, socket.SOCK_STREAM)
c.sendall('HTTP/1.1 200 OK\r\nContent-Length: 6\r\nContent-Type: text/plain\r\n\r\nhello\n'.encode())
c.shutdown(socket.SHUT_WR)
c.close()
except: print(traceback.format_exc())
if __name__ == '__main__':
pipe_recv, pipe_send = multiprocessing.Pipe()
proc = multiprocessing.Process(target=loop, args=(pipe_recv,))
proc.start()
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(('localhost', 9000))
s.listen()
while True:
conn, addr = s.accept()
reduction.send_handle(pipe_send, conn.fileno(), proc.pid)
我可以curl
它:
curl -v http://localhost:9000/
* Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 9000 (#0)
> GET / HTTP/1.1
> Host: localhost:9000
> User-Agent: curl/7.47.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Content-Length: 6
< Content-Type: text/plain
<
hello
* Connection #0 to host localhost left intact
当我有一个或几个循环的 curl-s 时,它工作得很好,但是如果我创建很多 'client' 或只是使用 apache 基准测试,例如,脚本崩溃:
Traceback (most recent call last):
File "/tmp/this-is-my-script", line 8, in loop
c = socket.fromfd(reduction.recv_handle(pipe), socket.AF_INET, socket.SOCK_STREAM)
File "/usr/lib/python3.5/multiprocessing/reduction.py", line 181, in recv_handle
return recvfds(s, 1)[0]
File "/usr/lib/python3.5/multiprocessing/reduction.py", line 160, in recvfds
len(ancdata))
RuntimeError: received 0 items of ancdata
我花了很多时间试图理解这一点,但没有成功。所以我放弃了问这个问题。 reduction
模块甚至没有记录在 3.5
中。这是否意味着我不应该使用它?
如果没有 - 我没有看到任何其他在进程之间共享套接字的可能性,有吗?
如果是 - 我想念什么?
终于!
- 无需调用
socket.fromfd()
。我的代码基于 this gist,不确定 python2,但在 3.5 中它肯定会导致不需要的套接字重复创建,而它又保留在 TIME_WAIT 中,如果调用socket.socket()
直接。
fromfd() 来源:
def fromfd(fd, family, type, proto=0):
nfd = dup(fd)
return socket(family, type, proto, nfd)
- 在发送方传输后必须关闭套接字
此外,无条件关闭子进程中的套接字导致 apache 基准测试挂起。完全没有
close()
就可以正常工作。
所以最终版本如下。它实际上不是多进程的,所以它会通过 -c
参数的 apache 基准测试失败。但这超出了问题的范围。
#!/usr/bin/env python3.5
import multiprocessing, socket, traceback
from multiprocessing import reduction
def loop(pipe_recv):
while True:
try:
conn = socket.socket(fileno=reduction.recv_handle(pipe_recv))
conn.sendall('HTTP/1.0 200 OK\r\nContent-Length: 6\r\nContent-Type: text/plain\r\n\r\nhello\n'.encode())
conn.shutdown(socket.SHUT_WR)
except: print(traceback.format_exc())
if __name__ == '__main__':
pipe_recv, pipe_send = multiprocessing.Pipe()
proc = multiprocessing.Process(target=loop, args=(pipe_recv,))
proc.start()
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(('localhost', 9000))
s.listen(100)
while True:
conn, addr = s.accept()
reduction.send_handle(pipe_send, conn.fileno(), proc.pid)
conn.close()