业务需求如下图. 一个业务既要通过webapi实时的接收处理任务, 又需要定时从数据库轮询, 还需要从socket接收数据后,
为了统一方便后面的编程. 和性能提高. 分析了一下, 程序结构设计如下.
分析后结果如下
数据处理线程是一样的任务, 线程再多也是一个类
业务入口则需要根据具体情况来实现 一个入口就是一个线程, 并且任务内容不同 . 需要是多个类.
本程序通过python实现的, webapi 用到了tornado框架,
定时循环则是简单的while循环
主程序启动代码 start.py
# 所有的数据都从 JobList 中获取的.
jobList = JobList()
# 启动主干活的线程1
scoring = DoScoringThread(jobList)
scoring.start()
# 启动主干活的线程2
scoring2 = DoScoringThread(jobList)
scoring2.start()
# 启动主干活的线程3
scoring3 = DoScoringThread(jobList)
scoring3.start()
# 从数据库循环取任务的线程
dbing = FromDBLoopGetJobThread(jobList)
dbing.start()
# 开启webapi服务
WebAPIServer.StartWebAPIServe(jobList)
干活的线程…
import threading
# from common.Job.JobList import GetOneJob
from common.Job.ScoringBLL import DoScoring
import time
import traceback
#干活的线程
class DoScoringThread(threading.Thread):
'''
自动打分线程
'''
def __init__(self,jobList):
threading.Thread.__init__(self)
self.jobList = jobList
def run(self):
while(True): #这一层确保发生错误仍然执行循环
try:
self.DoLoop() #发生错误仍然执行循环
except Exception as ex:
traceback.print_exc()
time.sleep(0.5) # 防止死循环消耗大量资源
def DoLoop(self):
#循环去任务池中取任务
while(True):
jobkey = self.jobList.GetOneJob()
if(jobkey == None):
print("线程", threading.currentThread().ident,"未取到任务,休眠...")
self.jobList.getThreadEvent().wait() # 没任务等待主线程的通知
else:
print("线程", threading.currentThread().ident,"取到任务,开始执行...")
DoScoring(jobkey)#
轮询数据库取任务的线程.
import threading
import time
import traceback
# from common.Job.JobList import AppendJob
class FromDBLoopGetJobThread(threading.Thread):
'''
自动从数据库取任务的线程
'''
def __init__(self,jobList):
self.jobList = jobList
threading.Thread.__init__(self)
def run(self):
while(True): #这一层确保发生错误仍然执行循环
try:
self.DoLoop() #发生错误仍然执行循环
except Exception as ex:
traceback.print_exc()
time.sleep(0.5) # 防止死循环消耗大量资源
def DoLoop(self):
#循环去任务池中取任务
while(True):
# 从数据库取数据
jobkey = "任务1111"
print("从DB新增任务",jobkey)
self.jobList.AppendJob(jobkey) #只要调用
time.sleep(1)
其实入口的调用很简单. 只要调用下面的代码即可.其它的代码自由发挥.
jobList.AppendJob(jobkey) # 添加的时候, 内部默认会通知工作的线程.
核心代码是 JobList.py 这个类
import threading
class JobList( ):
'''
工作任务列表
'''
def __init__(self):
self.threadevent = threading.Event()
self.lock = threading.RLock()
self.JobList=[] # 任务列表
def AppendJob(self,jobkey):
'''
追加任务
'''
self.lock.acquire() #加锁
self.JobList.append(jobkey)
self.lock.release() # 解锁
self.threadevent.set() # 通知所有工作的线程, 有活干了, 线程就会从wait后面开始执行调用 GetOneJob 来获取任务
def getThreadEvent(self):
'''
获取事件,一般是工作线程用来调用wait用
'''
return self.threadevent
def GetOneJob(self):
'''
获取一个任务
'''
self.lock.acquire()#加锁
jobkey = None
if len(self.JobList) == 0:
self.threadevent.clear() # 通知所有工作的线程, 已经没有任务了不要再来取了. 其它线程运行到wait的时候就会挂起, 直到set被调用
else:
jobkey = self.JobList.pop(0)
self.lock.release()# 释放线程锁
return jobkey
WebApi的入口代码也一样很简单, 我就不贴了.
在合适的地方调用即可
jobList.AppendJob(jobkey) # 添加的时候, 内部默认会通知工作的线程.
主要是用的多线程中的 threading.Event() 和 threading.RLock().