import threading import time import multiprocessing import importlib.util from multiprocessing.managers import BaseManager from myutils.ConfigManager import myCongif from myutils.MyLogger_logger import LogHandler from core.ACLModelManager import ACLModeManger from core.DataStruct import ModelinData,ModeloutData from threading import Lock #2024-10-14model处理调整为独立子进程 def model_process(device,model,model_platform,m_p_status,brun,in_mq,out_mq): # 初始化模型运行资源 context = None if model_platform == "acl": # ACL线程中初始化内容 context = ACLModeManger.pro_init_acl(device) # 初始化acl资源,并创建context # 初始化模型资源 -- 加载模型文件 ret = model.init_acl_resource() # 加载和初始化离线模型文件--om文件 if not ret: print("初始化模型资源出错,退出线程!") m_p_status.value = 2 return #执行工作 m_p_status.value = 1 use_time = 0 icount = 0 while brun.value: try: inData = in_mq.get(timeout=0.1) #空时-block,直到有值 #(self,channel_id,img,image,scale_ratio, pad_size): except: #print("in_mq_空") continue if inData: #print(f"{time.time()}--{inData.channel_id}--数据取出进行处理!") s_time = time.time() outputs = model.execute([inData.img,])#创建input,执行模型,返回结果 --失败返回None e_time = time.time() outdata = ModeloutData(inData.image,inData.scale_ratio,inData.pad_size,outputs,inData.channel_id) del inData.img #结果输出 if out_mq.full(): tmp = out_mq.get() #print("model_输出mq满!") del tmp out_mq.put(outdata) # 需要确保out_mq只有在这里put # else: #正常情况不会执行到该条件 # time.sleep(0.01) icount += 1 use_time += (e_time - s_time) if icount == 500: avg_time = use_time / 500 print(f"model_process耗时--{avg_time}秒") use_time = 0 icount = 0 #结束进程,释放资源 m_p_status.value = 0 while not in_mq.empty(): try: in_mq.get_nowait() # Get without blocking except Exception as e: break # In case of any unexpected errors # 反初始化 if model_platform == "acl": try: model.release() # 释放模型资源资源 # 删除模型对象 del model # 释放ACL资源 ACLModeManger.pro_del_acl(device,context) except Exception as e: print(e) class ModelNode: def __init__(self,device,model_path,ch_max_count=1): self.device = device self.model_path = model_path self.channel_id = [] #channel_id_list self.model = None #模型对象 self.ch_max_count = ch_max_count self.ch_count = 0 #关联启动的通道数量 self.count_Lock = Lock() #count的维护锁 self.model_platform = myCongif.get_data("model_platform") self.logger = LogHandler().get_logger("ModelNode") #分发线程相关 self.model_out_th = None self.channel_dict = {} self.cdict_Lock = Lock() self.in_mq_Lock = Lock() self.last_in_c_id = 0 #独立进程方案--共享参数 self.process = None self.imq_count = ch_max_count * 20 #一个通道20帧缓冲区间 self.in_mq = multiprocessing.Queue(maxsize=self.imq_count) self.out_mq = multiprocessing.Queue(maxsize=self.imq_count) #调整结构,多线程(预处理)-》in_mq-子进程-out_mq-》线程分发outdata->多线程(后处理) self.brun = multiprocessing.Value('b',True) #brun.value = False,brun.value = True self.m_p_status = multiprocessing.Value('i',0) def __del__(self): pass def _import_model(self, model_path, threshold=0.5, iou_thres=0.5): ''' 根据路径,动态导入模块 :param model_path: 模块路径 :param threshold: 置信阈值 :param iou_thres: iou阈值 :return: ''' try: module_path = model_path.replace("/", ".").rsplit(".", 1)[0] print(module_path) # 动态导入模块 module = importlib.import_module(module_path) # 从模块中获取指定的类 Model = getattr(module, "Model") # 使用 Model 类 model_instance = Model(model_path, threshold, iou_thres) return model_instance except ModuleNotFoundError as e: print(f"Module not found: {e}") return None except AttributeError as e: print(f"Class not found in module: {e}") return None except Exception as e: print(f"An unexpected error occurred: {e}") return None def pro_add_data(self,data): # try: # self.in_mq.put(data,timeout=0.1) # except multiprocessing.queues.Full: # print("mdel_inmq输入满!") # del data with self.in_mq_Lock: if self.ch_count>1 and self.last_in_c_id == data.channel_id: return self.last_in_c_id = data.channel_id if self.in_mq.full(): tmp = self.in_mq.get() #print("mdel_inmq输入满!") del tmp self.in_mq.put(data) # 需要确保out_mq只有在这里put def _modle_th(self): '''根据channel_id分发out_data到out_mq''' s_time = time.time() icount = 0 while self.brun.value: try: outdata = self.out_mq.get(timeout=0.1) except: continue with self.cdict_Lock: if outdata.channel_id in self.channel_dict: self.channel_dict[outdata.channel_id].myappend(outdata) #后面就交给后处理线程了 else: print(f"{outdata.channel_id}不在channel_dict里面") # icount += 1 # if icount ==500: # e_time = time.time() # use_time = (e_time-s_time) /500 # print(f"{self.channel_id}_modle_th耗时--{use_time}秒") # s_time = time.time() # icount = 0 #2024-10-14调整为独立进程执行 -- 一个线程一个MQ MyDeque def start_model_th(self,channel_id,out_mq): with self.count_Lock: with self.cdict_Lock: if channel_id in self.channel_dict: print(f"{channel_id}已经在channel_dict内") return #这个可以删除老的,新增新的--后续验证,若需要则进行修改 self.channel_dict[channel_id] = out_mq #增加一个记录 print(f"新增一个channel节点--{channel_id}") if self.ch_count == 0: #第一次启动--需要启动处理线程和进程 #加载自定义模型文件 self.model = self._import_model(self.model_path) # 动态加载模型处理文件py --置信阈值一直没使用 if not self.model: self.logger.error("自定义模型文件加载失败,不启动model子进程") self.m_p_status.value = 2 return self.brun.value = True #创建outMQ的分发线程 self.model_out_th = threading.Thread(target=self._modle_th) self.model_out_th.start() # 创建子进程 self.process = multiprocessing.Process(target=model_process, args=(self.device,self.model,self.model_platform, self.m_p_status,self.brun,self.in_mq,self.out_mq)) self.process.start() self.ch_count += 1 #有通道调用一次就加一 def stop_model_th(self,channel_id): with self.count_Lock: with self.cdict_Lock: if channel_id in self.channel_dict: del self.channel_dict[channel_id] self.ch_count -= 1 if self.ch_count == 0: #所有通道结束 self.brun.value = False self.model_out_th.join() #等待线程结束 self.model_out_th = None self.process.join() #等待子进程结束 self.process = None