从哪开始阅读源代码

代码树

执行命令:

tree -I '*.pyc'

先看看gunicorn的目录树:

gunicorn
├── app
│   ├── base.py
│   ├── djangoapp.py
│   ├── __init__.py
│   ├── pasterapp.py
│   └── wsgiapp.py
├── arbiter.py
├── config.py
├── debug.py
├── errors.py
├── glogging.py
├── http
│   ├── body.py
│   ├── errors.py
│   ├── __init__.py
│   ├── message.py
│   ├── parser.py
│   ├── _sendfile.py
│   ├── unreader.py
│   └── wsgi.py
├── __init__.py
├── logging_config.py
├── management
│   ├── commands
│   │   ├── __init__.py
│   │   └── run_gunicorn.py
│   └── __init__.py
├── pidfile.py
├── sock.py
├── util.py
└── workers
    ├── async.py
    ├── base.py
    ├── geventlet.py
    ├── ggevent.py
    ├── ggevent_wsgi.py
    ├── gtornado.py
    ├── __init__.py
    ├── sync.py
    └── workertmp.py

从脚本命令开始

就从脚本命令gunicorn和gunicorn_django开始

gunicorn

#!/home/hzg/mypy/bin/python
# EASY-INSTALL-ENTRY-SCRIPT: 'gunicorn==0.13.4','console_scripts','gunicorn'
__requires__ = 'gunicorn==0.13.4'
import sys
from pkg_resources import load_entry_point

sys.exit(
   load_entry_point('gunicorn==0.13.4', 'console_scripts', 'gunicorn')()
)

gunicorn_django

#!/home/hzg/mypy/bin/python
# EASY-INSTALL-ENTRY-SCRIPT: 'gunicorn==0.13.4','console_scripts','gunicorn_django'
__requires__ = 'gunicorn==0.13.4'
import sys
from pkg_resources import load_entry_point

sys.exit(
   load_entry_point('gunicorn==0.13.4', 'console_scripts', 'gunicorn_django')()
)

这是eggs文件的规范,实际上调用入口,可以从entry_points.txt看出来:

entry_points.txt:

[console_scripts]
gunicorn=gunicorn.app.wsgiapp:run
gunicorn_django=gunicorn.app.djangoapp:run
gunicorn_paster=gunicorn.app.pasterapp:run

注意在[console_scripts]部分,有

  • gunicorn <–> gunicorn.app.wsgiapp:run
  • gunicorn_django <–> gunicorn.app.djangoapp:run

那么,我们就从gunicorn/app目录下开始,从wsgiapp.py, djangoapp.py开始。

wsgiapp.py

 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
import os
import sys

from gunicorn import util
from gunicorn.app.base import Application

class WSGIApplication(Application):

    def init(self, parser, opts, args):
        if len(args) != 1:
            parser.error("No application module specified.")

        self.cfg.set("default_proc_name", args[0])
        self.app_uri = args[0]

        sys.path.insert(0, os.getcwd())

    def load(self):
        return util.import_app(self.app_uri)

def run():
    """\
    The ``gunicorn`` command line runner for launcing Gunicorn with
    generic WSGI applications.
    """
    from gunicorn.app.wsgiapp import WSGIApplication
    WSGIApplication("%prog [OPTIONS] APP_MODULE").run()

gunicorn.app.wsgiapp:run最终是调用其中的一个函数run(),焦点集中在上述代码的最后两行,创建WSGIApplication后,立刻执行run()。

djangoapp.py

 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
55
56
57
58
59
60
61
62
63
ENVIRONMENT_VARIABLE = 'DJANGO_SETTINGS_MODULE'

class DjangoApplication(Application):

    def init(self, parser, opts, args):
        self.global_settings_path = None
        self.project_path = None
        if args:
            self.global_settings_path = args[0]
            if not os.path.exists(os.path.abspath(args[0])):
                self.no_settings(args[0])

    def get_settings_modname(self):
        from django.conf import ENVIRONMENT_VARIABLE

        # get settings module
        settings_modname = None
        if not self.global_settings_path:
            project_path = os.getcwd()

        # ......

    def setup_environ(self, settings_modname):
        from django.core.management import setup_environ

        # setup environ
        # ......

    def no_settings(self, path, import_error=False):
        if import_error:
            error = "Error: Can't find '%s' in your PYTHONPATH.\n" % path

        # .......

    def activate_translation(self):
        from django.conf import settings
        from django.utils import translation
        translation.activate(settings.LANGUAGE_CODE)

    def validate(self):
        """ Validate models. This also ensures that all models are
        imported in case of import-time side effects."""
        from django.core.management.base import CommandError
        from django.core.management.validation import get_validation_errors
        # ......

    def load(self):
        from django.core.handlers.wsgi import WSGIHandler

        self.setup_environ(self.get_settings_modname())
        self.validate()
        self.activate_translation()
        return WSGIHandler()

# ......

def run():
  """\
  The ``gunicorn_django`` command line runner for launching Django
  applications.
  """
  from gunicorn.app.djangoapp import DjangoApplication
  DjangoApplication("%prog [OPTIONS] [SETTINGS_PATH]").run()

gunicorn.app.djangoapp:run最终是调用其中的一个函数run(),焦点集中在上述代码的最后两行,创建DjangoApplication后,立刻执行run()。

尽管DjangoApplication定义了不少方法,但注意与WSGIAppliction的骨架一样,实际上就定义了两个方法:

  • init()
  • load()

最关键的方法run(),估计就是从父类Application里继承而来。