上一篇文章讲thread模块的使用,我们接下来看threading模块怎么使用。
threading模块对象
对象 |
描述 |
Thread |
一个线程的执行对象 |
Lock |
锁对象 |
RLock |
可重入锁对象,使单线程可以再次获得已经获得了的锁(递归锁定) |
Condition |
条件变量,让一个线程停下来,等待其它线程满足了某个条件 |
Event |
事件对象,通用的条件变量 |
Semaphore |
信号量 |
BoundedSemaphore |
与Semaphore类似,只是它不允许超过初始值 |
Timer |
与Thread相似,不过它要等待一段时间才开始运行 |
threading的Thread类是最主要的运行对象。
Thread对象的函数
函数 |
描述 |
start() |
线程开始执行 |
run() |
线程功能函数 |
join(timeout=None) |
程序挂起,直到线程结束;如果给了timeout,则最多阻塞timeout秒 |
getName() |
返回线程名字 |
setName(name) |
设置线程名字 |
isAlive() |
这个线程是否还在执行 |
isDaemon() |
返回线程的daemon标志 |
setDaemon(daemonic) |
设置线程的daemon属性,一定要在调用start()函数前调用 |
使用Thread类,我们介绍三种方法来创建线程。
● 创建一个Thread的实例,传给它一个函数
● 创建一个Thread的实例,传给它一个可调用的类对象
● 从Thread派生出一个子类,创建一个这个子类的实例
下面看第一种,创建一个Thread的实例,传给它一个函数
我们将初始化一个Thread对象,把函数(及其参数)传进去。这种方式实例化一个Thread与调用thread.start_new_thread()之间的最大区别就是,新线程不会立即开始。当你创建线程对象又不想立即开始执行的时候,这是很有用的。
#coding: utf-8 import threading from time import sleep, ctime loops = [4,2] def loop(nloop, nsec): print ‘loop‘, nloop, ‘start at:‘, ctime() print ‘loop %d 挂起%d秒‘ % (nloop, nsec) sleep(nsec) print ‘loop‘, nloop, ‘done at:‘, ctime() def main(): print ‘main thread start!‘ threads = [] #线程列表 nloops = range(len(loops)) for i in nloops: t = threading.Thread(target=loop, args=(i, loops[i])) threads.append(t) for i in nloops: threads[i].start() for i in nloops: threads[i].join() #等待线程结束 print ‘all done at:‘, ctime() if __name__ == ‘__main__‘: main()
运行结果:
这种方式就省了管理一堆锁的功夫了,只要对每个线程调用join()函数,就会等到线程结束。
另外,如果你的主线程除了等线程结束外,还有其它的事情要做(如处理或等待其它的客户请求),那就不用调用join()。一旦线程启动后,就会一直运行,直到线程的函数结束,退出为止。所以只有在你要等待线程结束的时候才要调用join()。
第二种方式,创建一个Thread的实例,传给它一个可调用的类对象
这种方式就是在第一种方式的情况下,将函数封装进类对象里面,由类对象提供功能函数。在创建Thread对象时会实例化这个类对象。
#coding: utf-8 import threading from time import sleep, ctime loops = [4,2] class Func(object): def __init__(self, func, args, name=""): self.name = name self.func = func self.args =args def __call__(self): self.res = self.func(*self.args) #如果python版本是1.6以下,就使用apply(self.func, self.args) def loop(nloop, nsec): print ‘loop‘, nloop, ‘start at:‘, ctime() print ‘loop %d 挂起%d秒‘ % (nloop, nsec) sleep(nsec) print ‘loop‘, nloop, ‘done at:‘, ctime() def main(): print ‘main thread start!‘ threads = [] #线程列表 nloops = range(len(loops)) for i in nloops: t = threading.Thread(target=Func(loop, (i, loops[i]), loop.__name__)) threads.append(t) for i in nloops: threads[i].start() for i in nloops: threads[i].join() #等待线程结束 print ‘all done at:‘, ctime() if __name__ == ‘__main__‘: main()
创建新线程的时候,Thread对象会调用我们的Func对象,这时会用到一个特殊函数__call__()。这是python的一个特性,只要定义类型的时候,实现__call__函数,这个类型就成为可调用的。比如实现了__call__函数的Func对象实例instance,形如instance(arg1,arg2,...)实际上调用的就是instance.__call__(arg1,arg2,...)
第三种方式,从Thread派生出一个子类,创建这个子类的实例
#coding: utf-8 import threading from time import sleep, ctime loops = [4,2] class MyThread(threading.Thread): def __init__(self, func, args, name=""): threading.Thread.__init__(self) self.name = name self.func = func self.args =args def run(self): self.res = self.func(*self.args) def loop(nloop, nsec): print ‘loop‘, nloop, ‘start at:‘, ctime() print ‘loop %d 挂起%d秒‘ % (nloop, nsec) sleep(nsec) print ‘loop‘, nloop, ‘done at:‘, ctime() def main(): print ‘main thread start!‘ threads = [] nloops = range(len(loops)) for i in nloops: t = MyThread(loop, (i, loops[i]), loop.__name__) threads.append(t) for i in nloops: threads[i].start() for i in nloops: threads[i].join() print ‘all done at:‘, ctime() if __name__ == ‘__main__‘: main()
这种方式使创建线程对象的代码更简洁。