|
|
|
import threading
|
|
|
|
import importlib.util
|
|
|
|
import time
|
|
|
|
import multiprocessing
|
|
|
|
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
|
|
|
|
s_time = time.time()
|
|
|
|
icount = 0
|
|
|
|
while brun.value:
|
|
|
|
try:
|
|
|
|
inData = in_mq.get(timeout=0.01) #空时-block,直到有值 #(self,channel_id,img,image,scale_ratio, pad_size):
|
|
|
|
except:
|
|
|
|
#print("in_mq_空")
|
|
|
|
continue
|
|
|
|
if inData:
|
|
|
|
outputs = model.execute([inData.img,])#创建input,执行模型,返回结果 --失败返回None
|
|
|
|
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.05)
|
|
|
|
icount += 1
|
|
|
|
if icount == 1000:
|
|
|
|
e_time = time.time()
|
|
|
|
use_time = (e_time - s_time) / 1000
|
|
|
|
print(f"model_process耗时--{use_time}秒")
|
|
|
|
s_time = time.time()
|
|
|
|
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,channel_id):
|
|
|
|
self.device = device
|
|
|
|
self.model_path = model_path
|
|
|
|
self.channel_id = channel_id
|
|
|
|
self.model = None #模型对象
|
|
|
|
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.process = None
|
|
|
|
self.in_mq = multiprocessing.Queue(maxsize=30)
|
|
|
|
self.out_mq = multiprocessing.Queue(maxsize=30) #调整结构,多线程(预处理)-》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
|
|
|
|
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=1)
|
|
|
|
except:
|
|
|
|
continue
|
|
|
|
with self.cdict_Lock:
|
|
|
|
if outdata.channel_id in self.channel_dict:
|
|
|
|
self.channel_dict[outdata.channel_id].myappend(outdata) #后面就交给后处理线程了
|
|
|
|
icount += 1
|
|
|
|
if icount ==1000:
|
|
|
|
e_time = time.time()
|
|
|
|
use_time = (e_time-s_time) /1000
|
|
|
|
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:
|
|
|
|
return #这个可以删除老的,新增新的--后续验证,若需要则进行修改
|
|
|
|
self.channel_dict[channel_id] = out_mq #增加一个记录
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
|
|