小編寫這篇文章的目的,主要是給大家講解一下,關(guān)于實(shí)現(xiàn)配置熱加載的方法,具體是怎么操作呢?下面就給大家詳細(xì)的解答下。
背景
由于最近有相關(guān)的工作需求,需要進(jìn)行增添相關(guān)的新功能,實(shí)現(xiàn)配置熱加載的功能。所謂的配置熱加載,也就是說當(dāng)服務(wù)收到配置更新消息之后,我們不用重啟服務(wù)就可以使用最新的配置去執(zhí)行任務(wù)。
如何實(shí)現(xiàn)
下面我分別采用多進(jìn)程、多線程、協(xié)程的方式去實(shí)現(xiàn)配置熱加載。
使用多進(jìn)程實(shí)現(xiàn)配置熱加載
如果我們代碼實(shí)現(xiàn)上使用多進(jìn)程,主進(jìn)程1來更新配置并發(fā)送指令,任務(wù)的調(diào)用是進(jìn)程2,如何實(shí)現(xiàn)配置熱加載呢?
使用signal信號(hào)量來實(shí)現(xiàn)熱加載
當(dāng)主進(jìn)程收到配置更新的消息之后(配置讀取是如何收到配置更新的消息的?這里我們暫不討論),主進(jìn)程就向進(jìn)子程1發(fā)送kill信號(hào),子進(jìn)程1收到kill的信號(hào)就退出,之后由信號(hào)處理函數(shù)來啟動(dòng)一個(gè)新的進(jìn)程,使用最新的配置文件來繼續(xù)執(zhí)行任務(wù)。
main函數(shù)
def main(): #啟動(dòng)一個(gè)進(jìn)程執(zhí)行任務(wù) p1=Process(target=run,args=("p1",)) p1.start() monitor(p1,run)#注冊信號(hào) processes["case100"]=p1#將進(jìn)程pid保存 num=0 while True:#模擬獲取配置更新 print( f"{multiprocessing.active_children()=},count={len(multiprocessing.active_children())}\n") print(f"{processes=}\n") sleep(2) if num==4: kill_process(processes["case100"])#kill當(dāng)前進(jìn)程 if num==8: kill_process(processes["case100"])#kill當(dāng)前進(jìn)程 if num==12: kill_process(processes["case100"])#kill當(dāng)前進(jìn)程 num+=1
signal_handler函數(shù)
def signal_handler(process:Process,func,signum,frame): #print(f"{signum=}") global counts if signum==17:#17 is SIGCHILD #這個(gè)循環(huán)是為了忽略SIGTERM發(fā)出的信號(hào),避免搶占了主進(jìn)程發(fā)出的SIGCHILD for signame in[SIGTERM,SIGCHLD,SIGQUIT]: signal.signal(signame,SIG_DFL) print("Launch a new process") p=multiprocessing.Process(target=func,args=(f"p{counts}",)) p.start() monitor(p,run) processes["case100"]=p counts+=1 if signum==2: if process.is_alive(): print(f"Kill{process}process") process.terminate() signal.signal(SIGCHLD,SIG_IGN) sys.exit("kill parent process")
完整代碼如下
#!/usr/local/bin/python3.8 from multiprocessing import Process from typing import Dict import signal from signal import SIGCHLD,SIGTERM,SIGINT,SIGQUIT,SIG_DFL,SIG_IGN import multiprocessing from multiprocessing import Process from typing import Callable from data import processes import sys from functools import partial import time processes:Dict[str,Process]={} counts=2 def run(process:Process): while True: print(f"{process}running...") time.sleep(1) def kill_process(process:Process): print(f"kill{process}") process.terminate() def monitor(process:Process,func:Callable): for signame in[SIGTERM,SIGCHLD,SIGINT,SIGQUIT]: #SIGTERM is kill signal. #No SIGCHILD is not trigger singnal_handler, #No SIGINT is not handler ctrl+c, #No SIGQUIT is RuntimeError:reentrant call inside<_io.BufferedWriter name='<stdout>'> signal.signal(signame,partial(signal_handler,process,func)) def signal_handler(process:Process,func,signum,frame): print(f"{signum=}") global counts if signum==17:#17 is SIGTERM for signame in[SIGTERM,SIGCHLD,SIGQUIT]: signal.signal(signame,SIG_DFL) print("Launch a new process") p=multiprocessing.Process(target=func,args=(f"p{counts}",)) p.start() monitor(p,run) processes["case100"]=p counts+=1 if signum==2: if process.is_alive(): print(f"Kill{process}process") process.terminate() signal.signal(SIGCHLD,SIG_IGN) sys.exit("kill parent process") def main(): p1=Process(target=run,args=("p1",)) p1.start() monitor(p1,run) processes["case100"]=p1 num=0 while True: print( f"{multiprocessing.active_children()=},count={len(multiprocessing.active_children())}\n") print(f"{processes=}\n") time.sleep(2) if num==4: kill_process(processes["case100"]) if num==8: kill_process(processes["case100"]) if num==12: kill_process(processes["case100"]) num+=1 if __name__=='__main__': main()
執(zhí)行結(jié)果如下
multiprocessing.active_children()=[<Process name='Process-1'pid=2533 parent=2532 started>],count=1 processes={'case100':<Process name='Process-1'pid=2533 parent=2532 started>} p1 running... p1 running... kill<Process name='Process-1'pid=2533 parent=2532 started> multiprocessing.active_children()=[<Process name='Process-1'pid=2533 parent=2532 started>],count=1 processes={'case100':<Process name='Process-1'pid=2533 parent=2532 started>} signum=17 Launch a new process p2 running... p2 running... multiprocessing.active_children()=[<Process name='Process-2'pid=2577 parent=2532 started>],count=1 processes={'case100':<Process name='Process-2'pid=2577 parent=2532 started>} p2 running... p2 running... multiprocessing.active_children()=[<Process name='Process-2'pid=2577 parent=2532 started>],count=1 processes={'case100':<Process name='Process-2'pid=2577 parent=2532 started>} p2 running... p2 running... multiprocessing.active_children()=[<Process name='Process-2'pid=2577 parent=2532 started>],count=1 processes={'case100':<Process name='Process-2'pid=2577 parent=2532 started>} p2 running... p2 running... kill<Process name='Process-2'pid=2577 parent=2532 started> signum=17 Launch a new process multiprocessing.active_children()=[<Process name='Process-2'pid=2577 parent=2532 stopped exitcode=-SIGTERM>],count=1 processes={'case100':<Process name='Process-3'pid=2675 parent=2532 started>} p3 running... p3 running... multiprocessing.active_children()=[<Process name='Process-3'pid=2675 parent=2532 started>],count=1
總結(jié)
好處:使用信號(hào)量可以處理多進(jìn)程之間通信的問題。
自媒體培訓(xùn)
壞處:代碼不好寫,寫出來代碼不好理解。信號(hào)量使用必須要很熟悉,不然很容易自己給自己寫了一個(gè)bug.(所有初學(xué)者慎用,老司機(jī)除外。)
還有一點(diǎn)不是特別理解的就是process.terminate()發(fā)送出信號(hào)是SIGTERM number是15,但是第一次signal_handler收到信號(hào)卻是number=17,如果我要去處理15的信號(hào),就會(huì)導(dǎo)致前一個(gè)進(jìn)程不能kill掉的問題。歡迎有對(duì)信號(hào)量比較熟悉的大佬,前來指點(diǎn)迷津,不甚感謝。
采用multiprocessing.Event來實(shí)現(xiàn)配置熱加載
實(shí)現(xiàn)邏輯是主進(jìn)程1更新配置并發(fā)送指令。進(jìn)程2啟動(dòng)調(diào)度任務(wù)。
這時(shí)候當(dāng)主進(jìn)程1更新好配置之后,發(fā)送指令給進(jìn)程2,這時(shí)候的指令就是用Event一個(gè)異步事件通知。
直接上代碼
scheduler函數(shù) def scheduler(): while True: print('wait message...') case_configurations=scheduler_notify_queue.get() print(f"Got case configurations{case_configurations=}...") task_schedule_event.set()#設(shè)置set之后,is_set為True print(f"Schedule will start...") while task_schedule_event.is_set():#is_set為True的話,那么任務(wù)就會(huì)一直執(zhí)行 run(case_configurations) print("Clearing all scheduling job...") event_scheduler函數(shù) def event_scheduler(case_config): scheduler_notify_queue.put(case_config) print(f"Put cases config to the Queue...") task_schedule_event.clear()#clear之后,is_set為False print(f"Clear scheduler jobs...") print(f"Schedule job...") 完整代碼如下 import multiprocessing import time scheduler_notify_queue=multiprocessing.Queue() task_schedule_event=multiprocessing.Event() def run(case_configurations:str): print(f'{case_configurations}running...') time.sleep(3) def scheduler(): while True: print('wait message...') case_configurations=scheduler_notify_queue.get() print(f"Got case configurations{case_configurations=}...") task_schedule_event.set() print(f"Schedule will start...") while task_schedule_event.is_set(): run(case_configurations) print("Clearing all scheduling job...") def event_scheduler(case_config:str): scheduler_notify_queue.put(case_config) print(f"Put cases config to the Queue...") task_schedule_event.clear() print(f"Clear scheduler jobs...") print(f"Schedule job...") def main(): scheduler_notify_queue.put('1') p=multiprocessing.Process(target=scheduler) p.start() count=1 print(f'{count=}') while True: if count==5: event_scheduler('100') if count==10: event_scheduler('200') count+=1 time.sleep(1) if __name__=='__main__': main() 執(zhí)行結(jié)果如下 wait message... Got case configurations case_configurations='1'... Schedule will start... 1 running... 1 running... Put cases config to the Queue... Clear scheduler jobs... Schedule job... Clearing all scheduling job... wait message... Got case configurations case_configurations='100'... Schedule will start... 100 running... Put cases config to the Queue... Clear scheduler jobs... Schedule job... Clearing all scheduling job... wait message... Got case configurations case_configurations='200'... Schedule will start... 200 running... 200 running...
總結(jié)
使用Event事件通知,代碼不易出錯(cuò),代碼編寫少,易讀。相比之前信號(hào)量的方法,推薦大家多使用這種方式。
使用多線程或協(xié)程的方式,其實(shí)和上述實(shí)現(xiàn)方式一致。唯一區(qū)別就是調(diào)用了不同庫中,queue和event.
#threading scheduler_notify_queue=queue.Queue() task_schedule_event=threading.Event() #async scheduler_notify_queue=asyncio.Queue() task_schedule_event=asyncio.Event()
綜上所述,就是小編給大家總結(jié)的,關(guān)于python方面的一些知識(shí)了,希望可以給大家?guī)韼椭?/p>
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/128005.html
摘要:而熱部署技術(shù)能夠幫助開發(fā)人員減少重新部署的等待時(shí)間。本文的目的為調(diào)研熱部署的技術(shù)現(xiàn)狀及其對(duì)開發(fā)效率的幫助,并簡單梳理其技術(shù)實(shí)現(xiàn)的難點(diǎn)。熱部署技術(shù)總結(jié)熱部署目前有多種技術(shù)實(shí)現(xiàn)官方開源商業(yè)。 開發(fā)、自測、聯(lián)調(diào)期間代碼可能會(huì)被頻繁地修改,通常即使只增加了一行代碼,都需要重啟容器以檢查執(zhí)行效果。而熱部署技術(shù)能夠幫助開發(fā)人員減少重新部署的等待時(shí)間。本文的目的為調(diào)研熱部署的技術(shù)現(xiàn)狀及其對(duì)開發(fā)效率的...
時(shí)間:2017年12月01日星期五說明:本文部分內(nèi)容均來自慕課網(wǎng)。@慕課網(wǎng):http://www.imooc.com 教學(xué)源碼:無 學(xué)習(xí)源碼:https://github.com/zccodere/s... 第一章:課程介紹 1-1 課程介紹 熱部署的使用場景 本地調(diào)式 線上發(fā)布 熱部署的使用優(yōu)點(diǎn) 無論本地還是線上,都適用 無需重啟服務(wù)器:提高開發(fā)、調(diào)式效率、提升發(fā)布、運(yùn)維效率、降低運(yùn)維成本 前置...
摘要:在項(xiàng)目根目錄下創(chuàng)建,通過這個(gè)文件來起服務(wù)。到這里為止,自動(dòng)刷新的內(nèi)容基本講完了。注意到一點(diǎn),目前自動(dòng)刷新都是刷新整個(gè)頁面。其中表示熱加載模塊,表示。后續(xù)我還會(huì)進(jìn)行更深入的學(xué)習(xí),希望和大家共同進(jìn)步。 本文主要介紹以下兩方面的內(nèi)容: webpack-dev-server自動(dòng)刷新 熱加載(Hot Module Replacement) 自動(dòng)刷新 webpack-dev-server提供了...
摘要:熱加載代表的是我們不需要重啟服務(wù)器,就能夠類檢測得到,重新生成類的字節(jié)碼文件無論是熱部署或者是熱加載都是基于類加載器來完成的。驗(yàn)證階段字節(jié)碼文件不會(huì)對(duì)造成危害準(zhǔn)備階段是會(huì)賦初始值,并不是程序中的值。 一、SpringBoot入門 今天在慕課網(wǎng)中看見了Spring Boot這么一個(gè)教程,這個(gè)Spring Boot作為JavaWeb的學(xué)習(xí)者肯定至少會(huì)聽過,但我是不知道他是什么玩意。 只是大...
閱讀 923·2023-01-14 11:38
閱讀 896·2023-01-14 11:04
閱讀 756·2023-01-14 10:48
閱讀 2055·2023-01-14 10:34
閱讀 961·2023-01-14 10:24
閱讀 840·2023-01-14 10:18
閱讀 510·2023-01-14 10:09
閱讀 588·2023-01-14 10:02