why is __init__ module in django project loaded twice
It should be loaded only once... per process. I'm guessing that manage.py
forks, and that two separate processes are launched. Could you print the result of os.getpid()
?
After learning the --noreload option from the above answer, I found that both
% django-admin help runserver
% manage.py help runserver
map to the below code in 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.',
)
Both django-admin.py and manage.py call
django.core.management.execute_from_command_line(sys.argv)
I then started to trace the Django code to better understand why the two PIDs when --noreload is not given.
In below, we have
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.
With the --noreload option, PPID executes inner_run() directly and skips the cPID subprocess for auto-reloading. If you kill either PPID or cPID, the whole process dies.