tornado 源码多进程(process.py)那段,发现他的多进程模型和一般常见的模型有点不一样,
- 常见的是主进程
bind -> listen -> accept
, 将 accept 返回的 socket 用子进程处理,
- tornado 则是
bind -> listen -> fork
, 在 listen 之后 fork,多个子进程共享 listen socket,每个子进程都 accept。
感觉会有错误或 “惊群” 现象,自己写了个程序测试一下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
| import socket import select import os import time import errno def child_epoll(): epoll = select.epoll() epoll.register(sock.fileno(), select.EPOLLIN) try: while True: events = epoll.poll(1) for fileno, event in events: if fileno == sock.fileno(): connection, address = sock.accept() print(os.getpid(), address) time.sleep(1) connection.close() finally: epoll.unregister(sock.fileno()) epoll.close() def start_child(i): pid = os.fork() if pid == 0: child_epoll() else: children[pid] = i sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0) sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) sock.setblocking(0) sock.bind(("0.0.0.0", 9700)) sock.listen(128) children = {} for i in range(4): start_child(i) time.sleep(2) print(children) while children: try: pid = status = os.wait() except Exception as e: if e.errno == errno.EINTR: continue raise if pid not in children: continue children.pop(pid)
|
然后用 ab 测测:ab -n 10 -c 5 http://127.0.0.1:9700/
可以发现每个连接都会只有一个进程去处理。虽然逻辑上没有错误,
http://static.usenix.org/event/usenix2000/freenix/full_papers/molloy/molloy.pdf 该论文说linux 2.6内核之后accept不会有惊群现象
Reference