gunicorn 工作原理
1.工作模型
gunicorn采用的是master-worker模型,一个master进程,多个worker进程。master进程负责管理worker进程
def spawn_workers(self):
workers = set(w.id for w in self.WORKERS.values())
for i in range(self.num_workers):
if i in workers:
continue
worker = Worker(i, self.pid, self.LISTENER, self.modname,
self.timeout)
pid = os.fork()
if pid != 0:
self.WORKERS[pid] = worker
continue
worker_pid = os.getpid()
try:
self.log.info("Worker %s booting" % worker_pid)
worker.run()
sys.exit(0)
except SystemExit:
raise
except:
self.log.exception("Exception in worker process.")
sys.exit(-1)
finally:
worker.tmp.close()
self.log.info("Worker %s exiting." % worker_pid)
下面我来个简化版的:
main.py
import os, socket, sys
from worker import Worker
print os.getpid(), 'process start'
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.setblocking(0)
sock.bind(("127.0.0.1", 5000))
sock.listen(2048)
for i in range(3):
w = Worker(i, os.getpid(), sock)
pid = os.fork()
if pid != 0:
continue
try:
w.run()
sys.exit(0)
except SystemExit:
raise
except:
sys.exit(-1)
# for read console
import time
time.sleep(200)
print 'end!'
# -*- coding: utf-8 -
import errno
import os
import select
import socket
CHUNK_SIZE = (16 * 1024)
def read_partial(sock, length):
while True:
try:
ret = select.select([sock.fileno()], [], [], 0)
if ret[0]: break
except select.error, e:
if e[0] == errno.EINTR:
continue
raise
data = sock.recv(length)
return data
class Worker(object):
def __init__(self, workerid, ppid, socket):
self.id = workerid
self.ppid = ppid
self.socket = socket
self.timeout = 10
self.alive = True
def run(self):
while self.alive:
nr = 0
while self.alive:
try:
client, addr = self.socket.accept()
buf = ''
while True:
data = read_partial(client, CHUNK_SIZE)
if not data: break
buf += data
print buf
nr += 1
except socket.error, e:
if e[0] in (errno.EAGAIN, errno.ECONNABORTED):
print 'socekt.error'
break # Uh oh!
raise
if nr == 0: break
while self.alive:
try:
ret = select.select([self.socket], [], [],
self.timeout)
if ret[0]:
break
except select.error, e:
if e[0] == errno.EINTR:
print 'select error', os.getpid()
break
raise
在
Linux
进行非阻塞的
socket
接收
数据
时经常出现Resource temporarily unavailable,errno代码为11(EAGAIN)
这表明你在非阻塞模式下调用了阻塞操作,在该操作没有完成就返回这个错误,
这表明你在非阻塞模式下调用了阻塞操作,在该操作没有完成就返回这个错误,
这个错误不会破坏socket的同步,可以不用管它,循环接着recv就可以。