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----
Work类

 说明:

  1. 传统方法创建线程后很可能将线程加入一个列表,然后迭代列表执行Thread.start(),但在此系统中,线程在创建时自动调用start(),因为所有线程调度工作已经封装在WorkManager类里面[line9]。
  2. 当Thread.start()调用时,将会启动Thread.run()的内容。python多线程机制线程执行任务是通过重写run()方法实现的。传统上,func和args会在创建时作为属性装载在Thread里面,通过run()里面启动func(args)。由于本系统加入了Queue,所以执行run()的时候是执行self.work_queue.get()向任务队列获取当前等待执行的参数集[行14]。
  3. 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类

 

 说明:

  1. 创建WorkManager时将任务方法func和参数集列表list_args装入实例中[line9]。
  2. 执行start()时,先将list_args中每个参数集提取出来,与func构成一个元组通过Queue.put()放入self.work_queue里面[line29,32]。
  3. 当所有任务列表建立好后,根据输入的线程池容量thread_pool_num创建线程[line23-25]。
  4. 多线程执行任务。由于Work.work_queue属性只是WorkManager.work_queue的一个指针,等于每条Thread都引用一个静态的任务列表work_queue[line25]。
  5. 任意Work线程完成一次func后,然后向work_queue申请新任务。当所有线程都无法get到新任务时,意味着work_queue为空。
  6. 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) 
Test.py

可以通过调整manager.start()里面的thread_pool_num,参考最终时间打印对比不同的线程池容量执行效果。

posted on 2013-04-10 15:37  0x9801  阅读(268)  评论(0)    收藏  举报

导航