首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >为什么django runserver命令启动2个进程?它们是干什么用的?以及如何区分代码中的每一个?

为什么django runserver命令启动2个进程?它们是干什么用的?以及如何区分代码中的每一个?
EN

Stack Overflow用户
提问于 2022-08-21 15:49:42
回答 2查看 61关注 0票数 0

在构建一些独立的Django应用程序(它将作为单独的守护进程线程在后台运行任务)时,我遇到了一个问题,因为在启动Django服务器时,似乎有两个MainThreads,每个线程都有一个不同的id。在深入研究这个问题之后,事实证明这是因为它实际上是两个过程。

经验:

  1. 运行django-admin startproject example && cd example启动一个新项目。
  2. 编辑example/settings.py,如果尚未导入imoprt os,则添加imoprt os,然后添加行print(f"Current processes ID:{os.getpid()}")
  3. 运行python manage.py runserver并查看输出
代码语言:javascript
复制
Current processes ID:426286
Current processes ID:426288
Watching for file changes with StatReloader
Performing system checks...

System check identified no issues (0 silenced).

You have 17 unapplied migration(s). Your project may not work properly until you apply the migrations for app(s): admin, auth, contenttypes, sessions.
Run 'python manage.py migrate' to apply them.

August 21, 2022 - 15:30:42
Django version 2.2.12, using settings 'example.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
  1. 更改任何文件(例如,只需向settings.py添加新行)并保存并查看输出
代码语言:javascript
复制
/pathtoproject/example/example/settings.py changed, reloading.
Current processes ID:426417
Watching for file changes with StatReloader
Performing system checks...

System check identified no issues (0 silenced).

You have 17 unapplied migration(s). Your project may not work properly until you apply the migrations for app(s): admin, auth, contenttypes, sessions.
Run 'python manage.py migrate' to apply them.

August 21, 2022 - 15:32:07
Django version 2.2.12, using settings 'example.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C. 

观察

manage.py runserver启动2个进程。其中一个一直保留到服务器停止为止,而另一个则在每次由于任何文件更改而重新加载项目时使用另一个id终止和重新创建。

版本细节

这已经在Django 2、3和4的多个版本上进行了测试,它总是像上面解释的那样启动2个进程。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2022-08-21 18:16:02

关于StateReloader的官方文档不多,但谢天谢地,我能够从代码中找到它。因此,在启动Django时,它基本上使用内置的python库subprocess来创建一个新的python进程,其参数与源代码中的在这一行完全相同。变量args的值将类似于

代码语言:javascript
复制
['/usr/bin/python', 'manage.py', 'runserver']

现在要问的一个非常重要的问题是,如果运行python manage.py runserver启动了一个新的python manage.py runserver实例,那么是什么阻止它通过一个闭环,一次又一次地创建一个新进程,直到操作系统在耗尽内存后崩溃?

这个问题的答案也是主要问题的答案,它在源代码中的这条线

代码语言:javascript
复制
        if os.environ.get(DJANGO_AUTORELOAD_ENV) == "true":

Django使用定义为DJANGO_AUTORELOAD_ENV的环境变量来确定当前进程是由Statereloader发起的Django进程还是Statereloader本身的进程。

DJANGO_AUTORELOAD_ENV这条线中定义的值是"RUN_MAIN",并且从Django 2到今天在Django 4中一直保持不变。

因此,如果在settings.py中添加以下示例代码:

代码语言:javascript
复制
if os.environ.get('RUN_MAIN') == 'true':
    print("This process has been initiated by Statereloader")

当您启动应用程序时,print语句将只执行一次,但是,每次该应用程序重新加载时,它都会再次执行。如果您希望只在启动应用程序一次就执行它,不管Statereloader如何,都不要再执行了,那么它应该是这样的:

代码语言:javascript
复制
if os.environ.get('RUN_MAIN') != 'true':
    print("This is the original process and will never restart")

另外,一个有用的提示是,如果您需要与Django一起运行一个后台任务,而不影响Django的工作方式,那么您可以在AppConfig.ready方法中启动一个守护进程线程,在检查RUN_MAIN环境变量之后如下所示。

代码语言:javascript
复制
from django.apps import AppConfig
import threading
import os


class RockNRollConfig(AppConfig):
    # ...

    def ready(self):
        if os.environ.get('RUN_MAIN') == 'true':
             threading.Thread(
                  name="YourDaemonThread",
                  target=your_thread_function,
                  daemon=True
             ).start()

这样你就可以放心:

  1. 一次只运行一个线程实例(除非启动Django服务器的多个实例)
  2. 每当Statereloader重新创建进程时,您的线程将与Django应用程序中的其他所有内容一起重新启动。
票数 0
EN

Stack Overflow用户

发布于 2022-08-21 16:12:39

这两个进程中的一个是自动重新加载程序.

与runserver一起使用-重新装载

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/73435965

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档