Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.

218 lines
9.8KB

  1. # -*- coding: utf-8 -*-
  2. import time
  3. import GPUtil
  4. from util import YmlUtils, FileUtils, LogUtils
  5. from loguru import logger
  6. from multiprocessing import Queue
  7. from concurrency.IntelligentRecognitionProcess import OnlineIntelligentRecognitionProcess, OfflineIntelligentRecognitionProcess
  8. from concurrency.MessagePollingThread import OfflineMessagePollingThread, OnlineMessagePollingThread
  9. from util import GPUtils
  10. '''
  11. 分发服务
  12. '''
  13. class DispatcherService():
  14. # 初始化
  15. def __init__(self):
  16. # 获取DSP环境所需要的配置
  17. self.content = YmlUtils.getConfigs()
  18. # 初始化日志
  19. LogUtils.init_log(self.content)
  20. # 检查视频保存地址,不存在创建文件夹,迁移初始化
  21. FileUtils.create_dir_not_exist(self.content["video"]["file_path"])
  22. # 记录当前正在执行的实时流分析任务
  23. self.onlineProcesses = {}
  24. # 记录当前正在执行的离线视频分析任务
  25. self.offlineProcesses = {}
  26. # 记录当前正在执行的图片分析任务
  27. # self.photoProcesses = {}
  28. self.onlineMpt = None
  29. self.offlineMpt = None
  30. # 服务调用启动方法
  31. def start_service(self):
  32. # 解决进程启动模型的环境问题,具体问题百度一下
  33. # torch.multiprocessing.set_start_method('spawn')
  34. # 启动实时,离线kafka消息拉取线程
  35. self.Kafka_message_listening()
  36. # 循环消息处理
  37. while True:
  38. time.sleep(1)
  39. # 检查任务进程运行情况,去除活动的任务
  40. self.check_process_task()
  41. gpu_ids = GPUtils.get_gpu_ids(self.content)
  42. if gpu_ids is not None and len(gpu_ids) > 0:
  43. ################## 消息驱动实时流分析进程执行 ##################
  44. onlineMsg = self.onlineMpt.poll()
  45. if onlineMsg is not None and len(onlineMsg) > 0:
  46. for k, v in onlineMsg.items():
  47. for m in v:
  48. try:
  49. msg = m.value
  50. # 校验kafka消息
  51. check_result = self.check_online_msg(msg)
  52. if not check_result:
  53. raise Exception("实时任务消息格式非法")
  54. if 'start' == msg.get("command"):
  55. logger.info("开始实时分析")
  56. self.startOnlineProcess(msg, self.content, gpu_ids)
  57. elif 'stop' == msg.get("command"):
  58. self.stopOnlineProcess(msg)
  59. else:
  60. pass
  61. except Exception as e:
  62. logger.error("实时消息监听异常:")
  63. logger.exception(e)
  64. ################## 消息驱动离线视频分析进程执行 ##################
  65. offlineMsg = self.offlineMpt.poll()
  66. if offlineMsg is not None and len(offlineMsg) > 0:
  67. for k, v in offlineMsg.items():
  68. for m in v:
  69. try:
  70. msg = m.value
  71. # 校验kafka消息
  72. check_result = self.check_offline_msg(msg)
  73. if not check_result:
  74. raise Exception("离线任务消息格式非法")
  75. if 'start' == msg.get("command"):
  76. logger.info("开始离线分析")
  77. self.startOfflineProcess(msg, self.content, gpu_ids)
  78. elif 'stop' == msg.get("command"):
  79. self.stopOfflineProcess(msg)
  80. else:
  81. pass
  82. except Exception as e:
  83. logger.error("离线消息监听异常:")
  84. logger.exception(e)
  85. else:
  86. logger.info("当前可用gpu数量: {}", gpu_ids)
  87. GPUtil.showUtilization()
  88. def startOnlineProcess(self, msg, content, gpu_ids):
  89. # 相同的requestId不在执行
  90. if self.onlineProcesses.get(msg.get("request_id"), None) is not None:
  91. logger.info("重复任务,请稍后再试!requestId:{}", msg.get("request_id"))
  92. raise Exception("重复任务,请稍后再试!requestId:{}".format(msg.get("request_id")))
  93. # 反馈队列
  94. fbQueue = Queue()
  95. # 图片队列
  96. imageQueue = Queue()
  97. # 创建在线识别进程并启动
  98. oirp = OnlineIntelligentRecognitionProcess(fbQueue, content, msg, imageQueue, gpu_ids)
  99. oirp.start()
  100. # 记录请求与进程映射
  101. self.onlineProcesses[msg.get("request_id")] = oirp
  102. def stopOnlineProcess(self, msg):
  103. ps = self.onlineProcesses.get(msg.get("request_id"), None)
  104. if ps is None:
  105. logger.info("未查询到该任务,无法停止任务!requestId:{}", msg.get("request_id"))
  106. raise Exception("未查询到该任务,无法停止任务!requestId:{}".format(msg.get("request_id")))
  107. ps.sendEvent({'command': 'stop'})
  108. # 检查实时、离线进程任务运行情况,去除不活动的任务
  109. def check_process_task(self):
  110. for requestId in list(self.onlineProcesses.keys()):
  111. if not self.onlineProcesses[requestId].is_alive():
  112. del self.onlineProcesses[requestId]
  113. for requestId in list(self.offlineProcesses.keys()):
  114. if not self.offlineProcesses[requestId].is_alive():
  115. del self.offlineProcesses[requestId]
  116. # 开启离线进程
  117. def startOfflineProcess(self, msg, content, gpu_ids):
  118. # 相同的requestId不在执行
  119. if self.offlineProcesses.get(msg.get("request_id"), None) is not None:
  120. logger.info("重复任务,请稍后再试!requestId:{}", msg.get("request_id"))
  121. raise Exception("重复任务,请稍后再试!requestId:{}".format(msg.get("request_id")))
  122. # 反馈队列
  123. fbQueue = Queue()
  124. # 图片队列
  125. imageQueue = Queue()
  126. # 创建在线识别进程并启动
  127. ofirp = OfflineIntelligentRecognitionProcess(fbQueue, content, msg, imageQueue, gpu_ids)
  128. ofirp.start()
  129. self.offlineProcesses[msg.get("request_id")] = ofirp
  130. def stopOfflineProcess(self, msg):
  131. ps = self.offlineProcesses.get(msg.get("request_id"), None)
  132. if ps is None:
  133. logger.info("未查询到该任务,无法停止任务!requestId:{}", msg.get("request_id"))
  134. raise Exception("未查询到该任务,无法停止任务!requestId:{}".format(msg.get("request_id")))
  135. ps.sendEvent({'command': 'stop'})
  136. # 校验实时kafka消息
  137. def check_online_msg(self, msg):
  138. requestId = msg.get("request_id")
  139. command = msg.get("command")
  140. models = msg.get("models")
  141. pull_url = msg.get("pull_url")
  142. push_url = msg.get("push_url")
  143. results_base_dir = msg.get("results_base_dir")
  144. if command is None:
  145. return False
  146. if requestId is None:
  147. return False
  148. if command == "start" and models is None:
  149. return False
  150. if models is not None:
  151. for model in models:
  152. if model.get("code") is None:
  153. return False
  154. if model.get("categories") is None:
  155. return False
  156. if command == "start" and pull_url is None:
  157. return False
  158. if command == "start" and push_url is None:
  159. return False
  160. if command == "start" and results_base_dir is None:
  161. return False
  162. return True
  163. # 校验实时kafka消息
  164. def check_offline_msg(self, msg):
  165. requestId = msg.get("request_id")
  166. models = msg.get("models")
  167. command = msg.get("command")
  168. original_url = msg.get("original_url")
  169. original_type = msg.get("original_type")
  170. results_base_dir = msg.get("results_base_dir")
  171. if command is None:
  172. return False
  173. if requestId is None:
  174. return False
  175. if command == 'start' and models is None:
  176. return False
  177. if models is not None:
  178. for model in models:
  179. if model.get("code") is None:
  180. return False
  181. if model.get("categories") is None:
  182. return False
  183. if command == 'start' and original_url is None:
  184. return False
  185. if command == 'start' and original_type is None:
  186. return False
  187. if command == 'start' and results_base_dir is None:
  188. return False
  189. return True
  190. # 实时、离线kafka消息监听
  191. def Kafka_message_listening(self):
  192. # 实时流分析消息拉取
  193. self.onlineMpt = OnlineMessagePollingThread('online_thread', {'content': self.content,
  194. 'topics': [self.content["kafka"]["topic"][
  195. "dsp-alg-online-tasks-topic"]]})
  196. # 离线视频分析消息拉取
  197. self.offlineMpt = OfflineMessagePollingThread('offline_thread', {'content': self.content,
  198. 'topics': [self.content["kafka"]["topic"][
  199. "dsp-alg-offline-tasks-topic"]]})
  200. # 开启监听线程
  201. self.onlineMpt.start()
  202. self.offlineMpt.start()