最近碰到个问题,需要telnet登录上千台机器去取主机名;其中有用户名密码交互部分,有需要延迟的部分,大概一次登录一次到处理完要10s,1000台机器串行处理就需要1000×10s,差不多三个小时,这是很难受的事情;
之前用thread的start_new_thread方法也可以实现,但是线程数量不好控制,没找到相关的控制线程数量的锁;
找了下关于Python的线程池,找到threadpool这么一个模块,可以满足我的需求,见:
http://chrisarndt.de/projects/threadpool/
我下的是版本1.2.2:
http://chrisarndt.de/projects/threadpool/download/threadpool-1.2.2.tar.bz2
放到当前目录或者python模块库都行,用法很简单,见:
第一行定义了一个线程池,表示最多可以创建poolsize这么多线程;
第二行是调用makeRequests创建了要开启多线程的函数,以及函数相关参数和回调函数,其中回调函数可以不写,default是无,也就是说makeRequests只需要2个参数就可以运行;
第三行用法比较奇怪,是将所有要运行多线程的请求扔进线程池,[pool.putRequest(req) for req in requests]等同于:
第四行是等待所有的线程完成工作后退出;
下面看下我的代码,使用线程池前后代码对比,不使用线程池:
用多线程的情况:
90s执行完毕,说明线程池还是很有用的东西。
自己实现:
最近在做一些文本处理方面的事情,考虑到程序利用并发性可以提高执行效率(不纠结特殊反例),于是入围的Idea如使用多进程或多线程达到期望的目标,对于进程或线程的创建是有代价的,那么我们是否可以实现一个线程池来达到已创建的线程反复使用从而使代价降低到最小呢?
当然可以,要想创建一个线程池,那么必须得有个容器来模拟“池”,在Python中,队列这样的数据结构就可以帮我们解决“池”这个问题,然而随之引来的 多线程之间数据处理同步问题,好在Python中有个Queue模块帮我们解决了这一棘手的问题,那么我们就可以实现一个线程池的雏形了。
2次开启不同的线程数运行结果如下:
上面实现了线程池的雏形,展现了基本原理,当然要想成为通用的API需要做很多的工作,希望本文能够起到抛砖引玉的效果。
threadpool例子:
1 #!/usr/bin/env python
2 #coding=gbk
3 import threadpool
4 import time,random
5
6 def hello(str):
7 time.sleep(2)
8 s = "world"
9 return str, s
10
11 def print_result(request, result):
12 print "the result is %s %r, and %s" % (request.requestID, result[0],result[1])
13
14 if __name__ == '__main__':
15 data = [random.randint(1,10) for i in range(20)]
16 print data
17 pool = threadpool.ThreadPool(5)
18 requests = threadpool.makeRequests(hello, [1,], print_result)
19 #requests = threadpool.makeRequests(hello, data, print_result)
20 [pool.putRequest(req) for req in requests]
21 pool.wait()
#!/usr/bin/env python
2 #coding=gbk
3 import threadpool
4 import time,random
5
6 def hello(str,st):
7 time.sleep(2)
8 s = "world"
9 return str, st, s
10
11 def print_result(request, result):
12 print "the result is %s %r, and %s, %s" % (request.requestID, result[0],result[1] ,result[2])
13
14 if __name__ == '__main__':
15 #data = [random.randint(1,10) for i in range(20)]
16 #print data
17 var1 = [1,2]
18 var2 = [2,4]
19 func_p = [(var1,None),(var2,None)]
20 pool = threadpool.ThreadPool(5)
21 requests = threadpool.makeRequests(hello, func_p, print_result)
22 #requests = threadpool.makeRequests(hello, data, print_result)
23 [pool.putRequest(req) for req in requests]
24 pool.wait()