首頁 後端開發 Python教學 django開發者模式中的autoreload是怎麼達成的

django開發者模式中的autoreload是怎麼達成的

Aug 19, 2017 pm 02:47 PM
django 開發者

    在開發django應用的過程中,使用開發者模式啟動服務是特別方便的一件事,只需要python manage.py runserver 就可以運行服務,並且提供了非常人性化的autoreload機制,不需要手動重啟程式就可以修改程式碼並看到回饋。剛接觸的時候覺得這個功能比較人性化,也沒覺得是什麼特別高大上的技術。後來有空就想著如果是我來實現這個autoreload會怎麼做,想了很久沒想明白,總有些地方理不清楚,看來第一反應真是眼高手低了。於是就特別花了一些時間研究了django是怎麼實現autoreload的,每一步都看源碼說話,不允許有絲毫的想當然:

1、runserver指令。在進入正題之前其實有一大段廢話,是關於runserver指令如何執行的,跟主題關係不大,就簡單帶一下:
指令列鍵入python manage.py runserver 後,django會去尋找runserver這個指令的執行模組,最後落在
django\contrib\staticfiles\management\commands\runserver.py模組上:


#django\contrib\staticfiles\management\commands\runserver.pyfrom django.core.management.commands.runserver import \
Command as RunserverCommandclass Command(RunserverCommand):
  help = "Starts a lightweight Web server for development and also serves static files."
登入後複製







#而這個Command的執行函數在這裡:


#django\core\management\commands\runserver.pyclass Command(BaseCommand):
  def run(self, **options):
  """  Runs the server, using the autoreloader if needed
  """  use_reloader = options['use_reloader']

  if use_reloader:
    autoreload.main(self.inner_run, None, options)
  else:
    self.inner_run(None, **options)
登入後複製


這裡有關於use_reloader的判斷。如果我們在啟動指令中沒有加--noreload,程式就會走autoreload.main這個函數,如果加了,就會走self.inner_run,直接啟動應用。

其實從autoreload.main的參數也可以看出,它應該是對self.inner_run做了一些封裝,autoreload的機制就在這些封裝當中,下面我們繼續跟著。

PS: 看原始碼的時候發現django的command模式還是實現的很漂亮的,值得學習。

2、autoreload模組。看autoreload.main():


#django\utils\autoreload.py:def main(main_func, args=None, kwargs=None):
  if args is None:
    args = ()
  if kwargs is None:
    kwargs = {}
  if sys.platform.startswith('java'):
    reloader = jython_reloader
  else:
    reloader = python_reloader

  wrapped_main_func = check_errors(main_func)
  reloader(wrapped_main_func, args, kwargs)
登入後複製


#這裡針對jpython和其他python做了區別處理,先忽略jpython;check_errors就是把對main_func進行錯誤處理,也先忽略。看python_reloader:


#django\utils\autoreload.py:def python_reloader(main_func, args, kwargs):
  if os.environ.get("RUN_MAIN") == "true":
    thread.start_new_thread(main_func, args, kwargs)
    try:
      reloader_thread()
    except KeyboardInterrupt:
      pass  else:
    try:
      exit_code = restart_with_reloader()
      if exit_code < 0:
        os.kill(os.getpid(), -exit_code)
      else:
        sys.exit(exit_code)
    except KeyboardInterrupt:
      pass
登入後複製
登入後複製

#第一次走到這裡時候,環境變數中RUN_MAIN變數不是"true", 甚至都沒有,所以走else, 看restart_with_reloader:


#django\utils\autoreload.py:def restart_with_reloader():    while True:
      args = [sys.executable] + ['-W%s' % o for o in sys.warnoptions] + sys.argv
    if sys.platform == "win32":
      args = ['"%s"' % arg for arg in args]
    new_environ = os.environ.copy()
    new_environ["RUN_MAIN"] = 'true'    exit_code = os.spawnve(os.P_WAIT, sys.executable, args, new_environ)
    if exit_code != 3:
      return exit_code
登入後複製


這裡首先起一個while循環, 內部先把RUN_MAIN改成了"true",然後用os.spawnve方法開一個子程序(subprocess),看看os.spawnve的說明:


   _spawnvef(mode, file, args, env, execve)
登入後複製


##其實就是再調一遍命令列,又走了一遍python manage.py runserver。

接著看restart_with_reloader裡的while循環,要注意的是while循環退出的唯一條件是exit_code!=3。 如果子進程不退出,就一直停在 os.spawnve這一步; 如果子進程退出,而退出碼不是3,while就被終結了;如果是3,繼續循環,重新創建子進程。從這個邏輯可以猜想autoreload的機制:當前進程(主進程)其實啥也不乾,就監視子進程的運行狀況,子進程才是真正幹事兒的;如果子進程以exit_code=3退出(應該由於檢測到了檔案修改),就再啟動一遍子進程,新程式碼自然就生效了;如果子進程以exit_code!=3退出,主進程也結束,整個django程式就算跪了。這只是猜想,下面接著來驗證。


3、子行程。上面其實有一個疑問,既然是重新啟動了一次,為什麼子行程不會接著生成子進程?原因就在於RUN_MAIN這個環境變量,主進程中把它改成了true,子進程走到python_reloader函數的時候:


#django\utils\autoreload.py:def python_reloader(main_func, args, kwargs):
  if os.environ.get("RUN_MAIN") == "true":
    thread.start_new_thread(main_func, args, kwargs)
    try:
      reloader_thread()
    except KeyboardInterrupt:
      pass  else:
    try:
      exit_code = restart_with_reloader()
      if exit_code < 0:
        os.kill(os.getpid(), -exit_code)
      else:
        sys.exit(exit_code)
    except KeyboardInterrupt:
      pass
登入後複製
登入後複製

#if條件滿足了,和主行程走了不一樣的邏輯分支。在這裡,先去開一個線程,運行main_func,就是上文的 Command.inner_run。這裡的thread模組是這麼import的:


#django\utils\autoreload.py:from django.utils.six.moves import _thread as thread
登入後複製


#這裡six模組的作用是相容於各種python版本:

######
[codeblock six]#django\utils\six.pyclass _SixMetaPathImporter(object):"""A meta path importer to import six.moves and its submodules.

This class implements a PEP302 finder and loader. It should be compatible
with Python 2.5 and all existing versions of Python3"""官网说明:# https://pythonhosted.org/six/Six: Python 2 and 3 Compatibility Library
Six provides simple utilities for wrapping over differences between Python 2 and Python 3. It is intended to support codebases that work on both Python 2 and 3 without modification. six consists of only one Python file, so it is painless to copy into a project.
登入後複製
############所以如果程式想在python2和python3上都能跑,且魯邦,six是重要的工具。之後抽個時間看下six,mark一下。 ######然後再開一個reloader_thread:############
=== change ==3)      change ==1)
登入後複製
############ensure_echo_on()其實還沒看明白,似乎是針對類unix系統檔案處理的,先略過;###USE_INOTIFY也是系統檔案操作相關的變量,根據inotify 是否可用選擇檢測檔案變化的方法。 ###while循環,每隔1秒偵測一下檔案狀態,如果是普通檔案有變化,行程退出,退出碼為3,主行程一看:退出碼是3,就重啟子行程。 。 。 。這樣就跟上面連上了;如果不是普通檔案變化,而是I18N_MODIFIED(.mo後綴的檔案變化,二進位函式庫檔案之類的),那就reset_translations ,大概意思是把已載入過的函式庫快取清理掉,下次重新加載。 ###

  以上就是autoreload機制的流程。其中還是有些細節不是特別清楚,例如不同作業系統檔案變化的偵測,但都是很細節的東西了,不涉及主流程。看完這些,我又問了自己一遍,如果是讓我設計autoreload機制會怎麼搞。現在我的答案是:直接把  django\utils\autoreload.py 檔案拿來用啊。其實這是很獨立的模組,而且特別通用,完全可以當作通用的autoreload解決方案,我還自己寫個毛啊。

以上是django開發者模式中的autoreload是怎麼達成的的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

怎麼看django版本 怎麼看django版本 Dec 01, 2023 pm 02:25 PM

查看django版本步驟:1、開啟終端機或命令提示字元視窗;2、確保已經安裝了Django,如果沒有安裝Django,可以使用套件管理工具來進行安裝,輸入pip install django命令即可;3、安裝完成後,可以使用python -m django --version來查看Django的版本。

Django vs. Flask:Python Web框架的比較分析 Django vs. Flask:Python Web框架的比較分析 Jan 19, 2024 am 08:36 AM

Django和Flask都是PythonWeb框架中的佼佼者,它們都有著自己的優點和適用場景。本文將對這兩個框架進行比較分析,並提供具體的程式碼範例。開發簡介Django是一個全功能的Web框架,它的主要目的是為了快速開發複雜的Web應用。 Django提供了許多內建的功能,例如ORM(物件關聯映射)、表單、認證、管理後台等。這些功能使得Django在處理大型

Django框架的優點和缺點:您需要知道的一切 Django框架的優點和缺點:您需要知道的一切 Jan 19, 2024 am 09:09 AM

Django是一個完整的開發框架,該框架涵蓋了Web開發生命週期的各個方面。目前,這個框架是全球最受歡迎的Web框架之一。如果你打算使用Django來建立自己的Web應用程序,那麼你需要了解Django框架的優點和缺點。以下是您需要知道的一切,包括具體程式碼範例。 Django優點:1.快速開發-Djang可以快速開發Web應用程式。它提供了豐富的庫和內

如何升級Django版本:步驟與注意事項 如何升級Django版本:步驟與注意事項 Jan 19, 2024 am 10:16 AM

如何升級Django版本:步驟和注意事項,需要具體程式碼範例引言:Django是一個功能強大的PythonWeb框架,它持續地進行更新和升級,以提供更好的效能和更多的功能。然而,對於使用較舊版Django的開發者來說,升級Django可能會面臨一些挑戰。本文將介紹如何升級Django版本的步驟和注意事項,並提供具體的程式碼範例。一、備份項目檔案在升級Djan

django版本區別是什麼 django版本區別是什麼 Nov 20, 2023 pm 04:33 PM

差異是:1、Django 1.x系列:這是Django的早期版本,包括1.0、1.1、1.2、1.3、1.4、1.5、1.6、1.7、1.8和1.9等版本。這些版本主要提供基本的Web開發功能;2、Django 2.x系列:這是Django的中期版本,包括2.0、2.1、2.2等版本;3、Django 3.x系列:這是Django的最新版本系列,包括3.0、3等版本。

怎麼查看django版本 怎麼查看django版本 Nov 30, 2023 pm 03:08 PM

查看django版本的方法:1、透過命令列查看,在終端機或命令列視窗中輸入「python -m django --version」命令;2、在Python互動式環境中查看,輸入「import django print(django. get_version())」代碼;3、檢查Django專案的設定文件,找到名為INSTALLED_APPS的列表,其中包含已安裝的應用程式資訊。

django是前端還是後端 django是前端還是後端 Nov 21, 2023 pm 02:36 PM

django是後端。詳細介紹:儘管Django主要是後端框架,但它與前端開發密切相關。透過Django的模板引擎、靜態檔案管理和RESTful API等功能,前端開發人員可以與後端開發人員合作,共同建立功能強大、可擴展的Web應用程式。

天貓精靈雲端存取服務升級:免費開發者收費 天貓精靈雲端存取服務升級:免費開發者收費 Jan 09, 2024 pm 10:06 PM

本站1月9日消息,天貓精靈日前發布雲端雲端接入服務升級的公告,升級後的雲端雲端存取服務從1月1日起從免費模式變更為付費。本站附新增功能與最佳化:優化雲端協議,提升裝置連線的穩定性;優化重點品類的語音控制;帳號授權升級:新增天貓精靈中開發者三方App的展示功能,幫助使用者更快更方便進行帳號綁定,同時新增開發者三方App帳號授權支援一鍵綁定天貓精靈帳號;新增終端屏顯互動能力,除語音互動外,用戶可透過app、帶屏音箱控制設備、取得設備狀態;新增智慧場景連動能力,新產品的屬性、事件,可作為狀態或事件上報,定義天貓

See all articles