kbengine進階的熱更新方案

imp.reload可以重載模塊,但是關鍵問題是已經實例化過的類是不會變的
比如:

  1. class AA:
  2.     def testaa():
  3.         DEBUG_MSG("test")
  4.                
  5. self.a=AA()

複製代碼

使用imp.reload熱更新後a還是不會變,需要重新把self.a.__class__=AA才能完成熱更新
這樣非常得不方便
一種可行的做法就是實例化類的時候把類都存到一個地方,然後熱更新的時候全部把它們的__class__修改一下就行了

一開始用的裝飾器的方式,但是有一些侷限性,還是用繼承的方式

  1.  
  2. g_allReloadObjectList=[]
  3. class Reload:
  4.     __reload__=True
  5.     def __init__(self):
  6.         g_allReloadObjectList.append(weakref.ref(self))

複製代碼

創建類的時候就像:

  1. class AA(Reload):
  2.     def __init__(self):
  3.         Reload.__init__(self)

複製代碼

就可以在實例化類的時候把實例存到g_allReloadObjectList裏面

下面的代碼寫得比較垃圾,但是簡單易懂:
reloadAllModule的功能是遍歷base cell common user_type幾個文件夾的所有文件,然後全部重載,感覺有點暴力,可以優化成只加載修改過的文件
同時把文件裏需要熱更新的類存到g_allClasses裏
然後把g_allReloadObjectList裏存的那些的實例的__class__全部改成g_allClasses裏的
reloadSystem.py

  1. import inspect
  2. import os
  3. import importlib
  4. import imp
  5. import copy
  6. import weakref
  7. import KBEngine
  8. from KBEDebug import *
  9. if 0:
  10.     from baseapp import KBEngine
  11. if 0:
  12.     from cellapp import KBEngine
  13.  
  14. #需要把此文件加入熱更新黑名單
  15. _blackList=["reloadSystem"]
  16. g_allClasses={}
  17.  
  18. g_allReloadObjectList=[]
  19. class Reload:
  20.     __reload__=True
  21.     def __init__(self):
  22.         g_allReloadObjectList.append(weakref.ref(self))
  23.  
  24. def reloadAllModule():
  25.     global g_allClasses
  26.     g_allClasses={}
  27.     #base cell common user_type文件夾內的所有py全部重載
  28.     if KBEngine.component=="baseapp":
  29.         sb=KBEngine.getResFullPath("base/kbemain.py")
  30.         sb=sb[:-10]
  31.         ll=len(sb)
  32.         for s in KBEngine.listPathRes("base","py"):
  33.             s=s[ll:-3]
  34.             s=s.replace('/','.')
  35.             mo=importlib.import_module(s)
  36.             _reloadModule(mo)
  37.     elif KBEngine.component=="cellapp":
  38.         sb=KBEngine.getResFullPath("cell/kbemain.py")
  39.         sb=sb[:-10]
  40.         ll=len(sb)
  41.         for s in KBEngine.listPathRes("cell","py"):
  42.             s=s[ll:-3]
  43.             s=s.replace('/','.')
  44.             mo=importlib.import_module(s)
  45.             _reloadModule(mo)
  46.     #reload common
  47.     sb=KBEngine.getResFullPath("common/cfunc.py")
  48.     sb=sb[:-8]
  49.     ll=len(sb)
  50.     for s in KBEngine.listPathRes("common","py"):
  51.         s=s[ll:-3]
  52.         s=s.replace('/','.')
  53.         mo=importlib.import_module(s)
  54.         _reloadModule(mo)
  55.     #reload userType
  56.     sb=KBEngine.getResFullPath("user_type/UserType.py")
  57.     sb=sb[:-11]
  58.     ll=len(sb)
  59.     for s in KBEngine.listPathRes("user_type","py"):
  60.         s=s[ll:-3]
  61.         s=s.replace('/','.')
  62.         mo=importlib.import_module(s)
  63.         _reloadModule(mo)
  64.  
  65.     _reloadAllObjects()
  66.  
  67.  
  68. """
  69. 重載模塊,然後把模塊裏面的需要重載的類全部加
  70. """
  71. def _reloadModule(mo):
  72.     if mo.__name__ in _blackList:
  73.         return
  74.     imp.reload(mo)
  75.     for name,Cls in inspect.getmembers(mo):
  76.         if getattr(Cls,'__reload__',False):
  77.             path=inspect.getsourcefile(Cls)
  78.             g_allClasses[path+Cls.__name__]=Cls
  79.  
  80.  
  81. def _reloadAllObjects():
  82.     delList=[]
  83.     for ref in g_allReloadObjectList:
  84.         obj=ref()
  85.         if obj:
  86.             n=inspect.getsourcefile(obj.__class__)+obj.__class__.__name__
  87.             if n in g_allClasses:
  88.                 obj.__class__=g_allClasses[n]
  89.             else:
  90.                 WARNING_MSG("not find Class "+n)
  91.         else:
  92.             delList.append(ref)
  93.     for ref in delList:
  94.         g_allReloadObjectList.remove(ref)

複製代碼

這樣就實現了即時切換__class__

並且可以用Tornado做一個類來接受socket命令然後調用globalData通知全部進程熱更新
然後在ide裏的externalTools裏做個發送socket的小工具,並且設置快捷鍵
然後只要寫了點代碼後按一下快捷鍵,服務端所有進程瞬間更新到最新的代碼,生活質量提升了不止一個檔次

如果誰有更好的熱更新方案歡迎補充

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章