为什么Django项目中的__init__模块加载了两次
我把
print 'Hello world!'
放进了我的django项目里的__init__.py
文件中。现在当我运行./manage.py runserver
时,我得到了
gruszczy@gruszczy-laptop:~/Programy/project$ ./manage.py runserver
Hello world!
Hello world!
Validating models...
0 errors found
为什么__init__.py
会被运行两次?它应该只加载一次。
3 个回答
0
有一个简单的方法可以找到答案,就是抛出一个异常。你可以在你的 init.py 文件里写点类似这样的代码:
import os
if os.path.isfile('/tmp/once.log'):
raise Exception
open('/tmp/once.log','w').write('first time')
这样你就可以查看错误追踪信息了。
5
在看到上面回答提到的 --noreload 选项后,我发现这两个
% django-admin help runserver
% manage.py help runserver
都对应到 Django 的代码文件 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.',
)
django-admin.py 和 manage.py 都调用了
django.core.management.execute_from_command_line(sys.argv)
接着,我开始追踪 Django 的代码,以更好地理解在没有使用 --noreload 选项时,为什么会有两个进程 ID(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.
使用 --noreload 选项时,PPID 直接执行 inner_run(),跳过了用于自动重载的 cPID 子进程。如果你杀掉了 PPID 或 cPID 中的任意一个,整个进程都会停止。
43
这个东西应该只加载一次……每个进程。我猜测一下,manage.py
可能会分叉,也就是说会启动两个不同的进程。你能打印一下 os.getpid()
的结果吗?