做完上篇的勘查後, 好奇之下順便看一下 runserver 怎麼實作 autoreload。
看 core/management/commands/runserver.py 會看到 autoreload.main(inner_run)。然後看 utils/autoreload.py, 稍微看原始碼, 配合 pdb觀察行為, 還滿簡單的。
inner_run 是真正處理 web request 的函式, autoreload 的行為如下:
- 在執行 inner_run 前, 先 fork 出 child process
- 讓 child process 開另一個 thread
- parent process 等待 fork 出來的 child process 結束
- child process 的一個 thread 每秒掃一次所有載入的 module, 看看原始碼是否有更新。有的話, 結束這個 process, 傳回 exit code 3
- child process 的另一個 thread 執行 inner_run
- parent process 發覺 child process 的 exit code 為 3 時, 重 fork 一次, 然後回到步驟 2
要注意的是, 要用 parent process 重 fork, 而不是 child process 自己再 fork 新 process。這樣才能確保由原本乾淨的狀態重讀全部 modules (parent process fork 完就沒做事了, 確保狀態沒有一絲改變)。
偵測程式更動的程式是 code_changed(), 關鍵部份是如何找出所有相關程式:
filter(lambda v: v, map(lambda m: getattr(m, "__file__", None), sys.modules.values()))
然後將 .pyc, .pyo 改為 .py, 接著記錄所有 py 檔的上次更新時間, 留待下次呼叫此函式時比對。從這段程式可看出, 包含 site-package 或 virtualenv 裡的程式也在偵測範圍內, 還挺方便的。
沒有留言:
張貼留言