Django 源碼閱讀(4):Django中自動加載機制

  • django 監聽文件變化實現自動重載,流程大致是:django服務啓動的同時,會啓動兩個進程,一個負責監控文件的變化,一個是主進程,如果文件發生變化,則會將退出當前進程,重新啓動一個子進程。

兩個進程

  • 重啓的設置在 run_with_reloader 函數中,該函數判斷是否設置了 RUN_MAIN 爲 True,但開始是沒有這個環境變量的,因此程序走 else 代碼塊,而在 restart_with_reloader 中,就設置了這個環境變量 new_environ = {**os.environ, DJANGO_AUTORELOAD_ENV: 'true'}
  • 在新的環境變量中,用 subprocess.call 啓動新子進程,而這個子進程運行的正是當前的命令(python manage.py runserver),現在 RUN_MAIN 爲 True 了,執行 start_django(reloader, main_func, *args, **kwargs) ,也就是啓動了一個 server。如果子進程不退出,就一直停在 subprocess.call 這一步; 如果退出碼不是 3,子進程退出,while 就被終結了;如果是 3,繼續循環,重新創建子進程。
  • 在此可以得出,django 的 autoreload 機制中,主進程其實也沒做什麼事,就是監控子進程的運行,如果子進程退出碼是 3,繼續創建子進程。
#django/utils/autoreload.py
DJANGO_AUTORELOAD_ENV = 'RUN_MAIN'
...
def restart_with_reloader():
    new_environ = {**os.environ, DJANGO_AUTORELOAD_ENV: 'true'}
    args = get_child_arguments()
    while True:
        exit_code = subprocess.call(args, env=new_environ, close_fds=False)
        if exit_code != 3:
            return exit_code
            
def run_with_reloader(main_func, *args, **kwargs):
    signal.signal(signal.SIGTERM, lambda *args: sys.exit(0))
    try:
        if os.environ.get(DJANGO_AUTORELOAD_ENV) == 'true':
            reloader = get_reloader()
            logger.info('Watching for file changes with %s', reloader.__class__.__name__)
            start_django(reloader, main_func, *args, **kwargs)
        else:
            exit_code = restart_with_reloader()
            sys.exit(exit_code)
    except KeyboardInterrupt:
        pass

實際問題

  • 當項目中用到了supervisord來守護django的進程,發現使用項目重啓的時候,特別的慢?
  • 但supervisord啓動django的時候監控的是兩個進程中的一個,所以實際上supervisord是無效的,同時還有可能會與主進程起衝突,佔用端口。

解決方案

  • 取消django的reload ,針對django的web服務可以添加 –noreload參數,即使用reload即可
  • 不使用supervisord,或者尋找其他的解決方案
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章