为什么django项目中的__init__模块加载了两次

gru*_*czy 11 python django

我放

print 'Hello world!'
Run Code Online (Sandbox Code Playgroud)

进入__init__.py我的django项目.当我./manage.py runserver现在跑,我得到

gruszczy@gruszczy-laptop:~/Programy/project$ ./manage.py runserver
Hello world!
Hello world!
Validating models...
0 errors found
Run Code Online (Sandbox Code Playgroud)

为什么__init__.py要跑两次?它应该只加载一次.

Tho*_*mas 30

它应该只加载一次...... 每个进程.我猜这个manage.py叉子,并且启动了两个独立的进程.你能打印出结果os.getpid()吗?

  • 对.Django使用两个进程来重新加载功能(即重新启动代码更改),如果运行`./manage.py runserver --noreload`,则只能获得一个进程. (21认同)

Leo*_*ang 5

从上面的答案中学习了 --noreload 选项后,我发现两者

% django-admin help runserver
% manage.py help runserver
Run Code Online (Sandbox Code Playgroud)

映射到 django/core/management/commands/runserver.py 中的以下代码

parser.add_argument(
    '--noreload', action='store_false', dest='use_reloader',
    help='Tells Django to NOT use the auto-reloader.',
)
Run Code Online (Sandbox Code Playgroud)

django-admin.py和manage.py都调用

django.core.management.execute_from_command_line(sys.argv) 
Run Code Online (Sandbox Code Playgroud)

然后我开始跟踪 Django 代码,以更好地理解为什么没有给出 --noreload 时的两个 PID。

在下面,我们有

class BaseCommand defined in management/base.py and 
class Command(BaseCommand) defined in management/commands/runserver.py

    execute_from_command_line(sys.argv) ==>> utility.execute() ==>>
    self.fetch_command(subcommand).run_from_argv(self.argv) ==>>
    self.execute(*args, **cmd_options) in management/base.py ==>>
        super().execute(*args, **options) in commands/runserver.py ==>>
    output = self.handle(*args, **options) in base.py ==>>
        self.run(**options) in commands/runserver.py  ==>>
    if use_reloader:
        autoreload.run_with_reloader(self.inner_run, **options)
    else:
        self.inner_run(None, **options)  // --noreload


    ParentPID run_with_reloader() ==>> DJANGO_AUTORELOAD_ENV = None ==>> 
    restart_with_reloader() only runs the 1st time by PPID ==>>
    ==>> subprocess.call(DJANGO_AUTORELOAD_ENV = true) ==>> child process cPID
    cPID run_with_reloader() ==>> "Watching for file changes with StatReloader"
    ==>> start_django(StatReloader, Command.inner_run) ==>>
    django_main_thread = threading.Thread(target=inner_run) and
    StatReloader.run(django_main_thread)
    ==>> Performing system checks... Starting development server at
    http://127.0.0.1:8080/

    The StatReloader(BaseReloader) will check file changes once per second.
    If there is a a file write => notify_file_changed(timestamp delta) =>
    trigger_reload() and PPID will spawn a new cPID and the old cPID is gone 
    so that we don't have to restart the runserver whenever there is a code change.
Run Code Online (Sandbox Code Playgroud)

使用--noreload选项,PPID直接执行inner_run()并跳过cPID子进程进行自动重新加载。如果杀死 PPID 或 cPID,整个进程就会终止。