Python 加入线程池机制的多线程系统
这是根据网上一个例子改良的版本。
系统描述:
- 所有线程只执行一个方法func()。
- func()对应的参数集为args,内部实现参数解释。
- 而每一个线程会对应不同的参数集数据,所以有一个参数集列表list_args且待执行任务总数等于len(list_args)。
- 通过队列Queue进行管理,创建容量为thread_pool_num个线程的线程池同时从任务列表WorkManager.work_queue中提取任务执行。
系统由Work和WorkManager两个class构成。Work继承python的threading.Thread,负责实现单一个线程的运作。而WorkManager则负责通过Queue实现线程调度。
1 import Queue 2 import threading 3 4 class Work(threading.Thread): 5 6 def __init__(self,work_queue): 7 threading.Thread.__init__(self) 8 self.work_queue = work_queue 9 self.start() 10 11 def run(self): 12 while True: 13 try: 14 func,args = self.work_queue.get(block=False) 15 func(args) 16 self.work_queue.task_done() 17 except Exception as e: 18 print str(e) 19 break 20 21 class WorkManager(): 22 # ----code----
说明:
- 传统方法创建线程后很可能将线程加入一个列表,然后迭代列表执行Thread.start(),但在此系统中,线程在创建时自动调用start(),因为所有线程调度工作已经封装在WorkManager类里面[line9]。
- 当Thread.start()调用时,将会启动Thread.run()的内容。python多线程机制线程执行任务是通过重写run()方法实现的。传统上,func和args会在创建时作为属性装载在Thread里面,通过run()里面启动func(args)。由于本系统加入了Queue,所以执行run()的时候是执行self.work_queue.get()向任务队列获取当前等待执行的参数集[行14]。
- run()在一个死循环里面执行,每执行完一次func都会执行Queue.task_done()向work_queue提示出列,知道无法从work_queue里面get到新任务[line12]。
1 import Queue 2 import threading 3 4 class Work(threading.Thread): 5 #----code---- 6 7 class WorkManager(): 8 9 def __init__(self,func,list_args): 10 self.work_queue = Queue.Queue() 11 self.threads = [] 12 self.job_func=func 13 self.job_args=list_args 14 15 def start(self,thread_pool_num=5): 16 self.__init_work_queue(len(self.job_args)) 17 self.__init_thread_pool(thread_pool_num) 18 self.__wait_allcomplete() 19 20 def check_queue(self): 21 return self.work_queue.qsize() 22 23 def __init_thread_pool(self,thread_pool_num): 24 for i in range(thread_pool_num): 25 self.threads.append(Work(self.work_queue)) 26 27 def __init_work_queue(self,jobs_num): 28 for i in range(jobs_num): 29 self.__add_job(self.job_func,self.job_args[i]) 30 31 def __add_job(self,func,args): 32 self.work_queue.put((func,args)) 33 34 def __wait_allcomplete(self): 35 for item in self.threads: 36 if item.isAlive(): 37 item.join()
说明:
- 创建WorkManager时将任务方法func和参数集列表list_args装入实例中[line9]。
- 执行start()时,先将list_args中每个参数集提取出来,与func构成一个元组通过Queue.put()放入self.work_queue里面[line29,32]。
- 当所有任务列表建立好后,根据输入的线程池容量thread_pool_num创建线程[line23-25]。
- 多线程执行任务。由于Work.work_queue属性只是WorkManager.work_queue的一个指针,等于每条Thread都引用一个静态的任务列表work_queue[line25]。
- 任意Work线程完成一次func后,然后向work_queue申请新任务。当所有线程都无法get到新任务时,意味着work_queue为空。
- WorkManager.__wait_allcomplete()保证将主线程阻塞直至所有任务完成[line24-37]。
测试效果:
1 from ThreadingWork import WorkManager 2 import time 3 4 def test_func(args): 5 time.sleep(0.2) 6 print 'doing job '+str(args) 7 8 test_list_args=[] 9 10 for i in range(99): 11 test_list_args.append(i) 12 13 start_time=time.time() 14 manager=WorkManager(test_func,test_list_args) 15 manager.start(10) 16 end_time=time.time() 17 print 'time used: ' + str(start_time-end_time)
可以通过调整manager.start()里面的thread_pool_num,参考最终时间打印对比不同的线程池容量执行效果。
浙公网安备 33010602011771号