ThreadPool的使用
Thursday, December 27th, 2007ThreadPool的使用
笔记: | gashero |
---|
1 简介
Nicky介绍给我使用的,其接口与其他很多线程池包装都差不多,不过因为只有一个模块,比较容易附带在程序中,所以研究下。 python threadpool 据介绍代码来自《Python in a Nutshell》的14.5节。
2 简单的使用
代码中给出的例子:
>>> pool=ThreadPool(poolsize) >>> requests=makeRequests(some_callable,list_of_args,callback) >>> [pool.putRequest(req) for req in requests >>> pool.wait()
可见使用步骤如下:
- 建立线程池对象,其实是个线程管理器
- 建立计算任务对象Request
- 将计算任务对象放入线程池当中
- 等待计算完成
3 接口文档
英文见 http://chrisarndt.de/en/software/python/threadpool/api/ 。
makeRequests(callable,args_list,callback=None,exc_callback=None)
创建多个计算请求,并允许有不同的参数。
参数列表中的每一个元素是两个元素的元组,分别是位置参数列表和关键字参数字典。
class ThreadPool
线程池类,发布工作请求并收集结果。
__init__(self,num_workers,q_size)
构造函数,设置线程池工作线程数量和最大任务队列长度。 num_workers 是初始化时的线程数量。如果 q_size>0 则会限制工作队列的长度,并且在工作队列满时阻塞继续插入工作请求的任务。
createWorkers(self,num_workers)
增加工作线程数量。
dismissWorkers(self,num_workers)
减少工作线程数量。
pool(self,block)
处理队列中的新结果。也就是循环的调用各个线程结果中的回调和错误回调。不过,当请求队列为空时会抛出 NoResultPending 异常,以表示所有的结果都处理完了。这个特点对于依赖线程执行结果继续加入请求队列的方式不太适合。
putRequest(self,request,block=True,timeout=0)
加入一个任务请求到工作队列。
wait(self)
等待执行结果,直到所有任务完成。
class WorkerThread
工作者线程,供ThreadPool内部使用,不必关注。其自定义方法也只有一个。
class WorkRequest
任务请求类。
__init__(self,callable,args=None,kwds=None,requestID=None,callback=None,exc_callback=None)
创建一个工作请求。
4 ThreadPool的递归任务管理问题
如果ThreadPool执行的任务中还会添加任务则需要多考虑几个问题。
如果一个这样的任务正在运行,尚未完成时任务列表就已经空了,那么ThreadPool会立即抛出 NoResultsPending 异常,以告知 wait() 方法所有任务都完成了。而事实上,还有一个线程尚未执行完成。
这种情况下,可以自己设置一个退出条件自己重新实现 wait() 方法。在循环中调用 poll(True) 方法。对于抛出的 NoResultsPending 异常视而不见。并自己设置循环的退出方法。
5 回调函数的使用
建立任务请求时有两种回调函数 callback 和 exc_callback ,他们的回调接口为:
callback(request,result) exc_callback(request,sys.exc_info())
其中 request 为 WorkRequest 对象。而 result 则是调用线程函数正确的返回结果。 sys.exc_info() 为发生异常时返回的信息。 sys.exc_info() 是一个拥有3个元素的元组。分别为:
- 异常类 :发生异常的类
- 异常实例 :如上异常类的实例,包含更多详细信息
- 跟踪信息 :traceback对象,可以显示错误的行号等等具体的错误信息
Warning
注意,如果没有设置 exc_callback 则发生异常时会将异常信息写入 callback 回调函数。如果同时没有设置 callback 和 exc_callback 则发生任何异常都不会有提示,根本无法调试。
5.1 使用 sys.exc_info() 信息
由于发生异常时返回的 sys.exc_info() 内容并不易读,所以可以用如下方式定制错误回调函数,将错误信息打印出来,或者可选的输出到日志文件。
import traceback def exc_callback(excinfo): errorstr=''.join(traceback.format_exception(*excinfo)) print errorstr
这样的显示结果就如同控制台中看到的错误跟踪一样了。