这个思路后来证明不能用于工作。
因为线程调用没有及时返回,所以不能用这种方式来重启服务。
但作为脑洞,也应该作个记录。
import os import shutil import datetime import threading import time import inspect import ctypes import hashlib PATH_DIR = "./" # 求字符串的md5码 def md5_str(org_str): md5obj = hashlib.md5() md5obj.update(str(org_str).encode("utf8")) _hash = md5obj.hexdigest() return str(_hash).upper() # 求一个文件的md5码 def get_file_md5(file_path): """ 获取文件md5值 :param file_path: 文件路径名 :return: 文件md5值 """ with open(file_path, 'rb') as f: return md5_str(f.read()) # 求一个文件夹下所有文件MD5码总和的MD5码 def get_path_files(files_path): md5_total = "" for parent, dirnames, filenames in os.walk(files_path, followlinks=True): for filename in filenames: file_path = os.path.join(parent, filename) md5_total += get_file_md5(file_path) return md5_str(md5_total) def _async_raise(tid, exctype): """raises the exception, performs cleanup if needed""" tid = ctypes.c_long(tid) if not inspect.isclass(exctype): exctype = type(exctype) res = ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, ctypes.py_object(exctype)) if res == 0: raise ValueError("invalid thread id") elif res != 1: # """if it returns a number greater than one, you're in trouble, # and you should call it again with exc=NULL to revert the effect""" ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, None) raise SystemError("PyThreadState_SetAsyncExc failed") # 配合上个_async_raise函数,优雅关闭线程 def stop_thread(thread): _async_raise(thread.ident, SystemExit) # 示例线程 class TestThread(threading.Thread): def run(self): print("begin") time.sleep(0.1) print('end') # 先启动线程,并进行文件夹内所有文件的MD5码求值 t = TestThread() t.start() t.join() files_md5 = get_path_files(PATH_DIR) while True: # 每隔sleep时间,作一次文件夹MD5码求值,如果发生了变化,说明文件更新,则关闭线程,然后重启线程,实现服务的热加载。 new_files_md5 = get_path_files(PATH_DIR) print(new_files_md5) if new_files_md5 == files_md5: pass else: files_md5 = new_files_md5 print("stop thread") try: stop_thread(t) except ValueError as e: print(e) except SystemError as e: print(e) finally: print("start thread") t = TestThread() t.start() t.join() time.sleep(5)
===============输出分隔线=============
AD45C4B0E8112D1E238A5E12DBD9735A
AD45C4B0E8112D1E238A5E12DBD9735A
AD45C4B0E8112D1E238A5E12DBD9735A
AD45C4B0E8112D1E238A5E12DBD9735A
AD45C4B0E8112D1E238A5E12DBD9735A
AD45C4B0E8112D1E238A5E12DBD9735A
AD45C4B0E8112D1E238A5E12DBD9735A
AD45C4B0E8112D1E238A5E12DBD9735A
5B63C272EB1642ADA89CA4602584C28C
stop thread
invalid thread id
start thread
begin
end
5B63C272EB1642ADA89CA4602584C28C
5B63C272EB1642ADA89CA4602584C28C
5B63C272EB1642ADA89CA4602584C28C
5B63C272EB1642ADA89CA4602584C28C
D4BB8E11D4936ABF35ABFF638673E753
stop thread
invalid thread id
start thread
begin
end
D4BB8E11D4936ABF35ABFF638673E753
D4BB8E11D4936ABF35ABFF638673E753
27071D9DC57B9D190CBFBAE05FDD76E2
stop thread
invalid thread id
start thread
begin
end
27071D9DC57B9D190CBFBAE05FDD76E2
27071D9DC57B9D190CBFBAE05FDD76E2
27071D9DC57B9D190CBFBAE05FDD76E2
27071D9DC57B9D190CBFBAE05FDD76E2
27071D9DC57B9D190CBFBAE05FDD76E2