由gunicorn执行程序入口说起, gunicorn version:20.x
def app(environ, start_response):
data = b"Hello, World!\n"
start_response("200 OK", [
("Content-Type", "text/plain"),
("Content-Length", str(len(data)))
])
return iter([data])
1. gunicorn入口点
使用gunicorn作为服务器执行程序时,执行命令为:gunicorn -w 2 gunicorn_app:app
对应到gunicorn中setup.py
入口点
[console_scripts]
gunicorn=gunicorn.app.wsgiapp:run
实际执行的是gunicorn.app.wsgiapp:run -w 2 gunicorn_app:app
2. 执行流程
2.1. 准备参数配置阶段
def run():
"""\
The ``gunicorn`` command line runner for launching Gunicorn with
generic WSGI applications.
"""
from gunicorn.app.wsgiapp import WSGIApplication
WSGIApplication("%(prog)s [OPTIONS] [APP_MODULE]").run()
WSGIApplication(init) ——> Application(run)——> BaseApplication(init, run) 首先执行Base类的初始化方法,
def __init__(self, usage=None, prog=None):
self.usage = usage
self.cfg = None
self.callable = None
self.prog = prog
self.logger = None
self.do_load_config()
def do_load_config(self):
"""
Loads the configuration
"""
try:
self.load_default_config()
self.load_config() #执行的是子类wsgi Application的覆盖方法
"""
1. parse() 使用argparse完成命令行参数生成得到匹配对象。parser.parse_args()进行参数解析
2. 执行wsgi类的init方法,设置app应用,app_uri='gunicorn_app:app'
3.chdir 工作目录
4. 加载配置:1. 通过-c指定的文件;或者系统环境下的GUNICORN_CMD_ARGS 变量;或者当前目录下的gunicorn.conf.py文件 2. 命令行参数。有文件,则加载文件,没有则加载输入的命令行参数。当同时配置了文件和命令参数时,配置会被命令参数覆盖。
"""
except Exception as e:
print("\nError: %s" % str(e), file=sys.stderr)
sys.stderr.flush()
sys.exit(1)
def load_default_config(self):
# init configuration
self.cfg = Config(self.usage, prog=self.prog) #装载配置项settings,使用到了元类
def run(self):
try:
Arbiter(self).run()
except RuntimeError as e:
print("\nError: %s\n" % e, file=sys.stderr)
sys.stderr.flush()
sys.exit(1)
2.2. 执行run
def run(self):
if self.cfg.print_config:
print(self.cfg) #是否打印配置信息,执行的是config类的`__str__`方法
if self.cfg.print_config or self.cfg.check_config:
try:
self.load()
except Exception:
msg = "\nError while loading the application:\n"
print(msg, file=sys.stderr)
traceback.print_exc()
sys.stderr.flush()
sys.exit(1)
sys.exit(0)
if self.cfg.spew:
debug.spew()
if self.cfg.daemon:
util.daemonize(self.cfg.enable_stdio_inheritance)
# set python paths
if self.cfg.pythonpath:
paths = self.cfg.pythonpath.split(",")
for path in paths:
pythonpath = os.path.abspath(path)
if pythonpath not in sys.path:
sys.path.insert(0, pythonpath)
#前面条件不满足,直接执行父类的方法
super().run() # Arbiter的run方法
Arbiter类主要做几件事:
- Arbiter.
__init__
self.setup(app) #app即gunicorn.app.Application实例
1.将一些配置数据赋值给Arbiter属性
2.设置env环境变量,参数raw_env
self.master_name = "Master"
- Arbiter.run()
self.init_signals() #Initialize master signal handling. Most of the signals are queued. Child signals only wake up the master
self.LISTENERS = sock.create_sockets(self.cfg, self.log, fds) # 创建socket 并进行监听,最多重试5次创建socket
self.manage_workers() ,完成的事情
1.执行worker数量值个self.spawn_workers(),即fork子进程spawn_worker;spawn_worker做了以下事:
I. 加载worker_class并实例化处理,即不同的worker类
II.父进程fork子进程之后return,子进程处理逻辑
III. 执行worker.init_process(),worker开始工作,交给支持的worker开始处理请求
IV.worker完成后, sys.exit(0)退出。
- workers
sync、eventlet、gevent、gevent_wsgi、gevent_pywsgi、tornado、gthread - init 初始化父进程pid、address、socket、cfg
- init_process 函数
init_signals() 信号初始化
load_wsgi() 调用应用程序
run() #由子类实现,即具体的worker, 接收请求并由handle_request处理请求,流程和werkzeug一样。
3. 总结
由gunicorn创建一个master主进程,然后主进程创建子进程,并传入父进程套接字。当进程alive的时候,会不断进行循环进行accept请求,交由wsgi应用处理。