threading模块,它不仅提供了Thread类,还提供了各种非常好用的同步机制。
threading 模块里所有的对象:
Thread
表示一个线程的执行的对象。
Lock
锁原语对象(和Thread模块里的锁对象相同)
RLock
可重入锁对象。使单线程可以再次获得一件获得了的锁(递归锁定)。
Condition
条件变量对象能让一个线程停下来,等待其他线程满足了某个条件。如状态的改变或值的改变。
Event
通用的条件变量。多个线程可以等待某个事件的发生,在事件发生后,所有的线程都会被激活。
Semaphore
为等待锁的线程提供一个类似”等候室“的结构。
BoundedSemaphore
与Sempahore类似,只是它不允许超过初始值
Timer
与Thread相似,只是它要等待一段时间后才开始运行。
守护线程
一个避免使用Thread模块的原因是,它不支持守护线程。当主线程退出时,所有的子线程无论
它们是否还在工作,都会被强行退出。
Threading模块支持守护线程,它们是这样工作的:守护线程一般是一个等待客户请求服务器,如果没有
客户提出请求,它就在那等着。如果你设定一个线程为守护线程,就表示你在说这个线程不重要,在进程
退出的时候,不用等待这个线程退出。如果主线程退出不用等待那些子线程完成,那就设定这些线程的
daemon属性,即在线程thread.start()开始前,调用setDaemon()函数设定线程的daemon标志(thread.setDaemon(True))
就表示这个线程“不重要”。如果想要等待子线程完成再退出,那就什么都不用做或者显式地调用thread.setDaemon(False)
以保证其daemon标志为False,可以调用thread.isDaemon()函数来判断其daemon标志的值。新的子线程会继承
其父线程的daemon标志,整个Python会在所有的非守护线程退出后才会结束,即进程中没有非守护线程存在的时候才结束。
threading的Thread 类
Threading的Thread类是你主要的运行对象。它有很多Thread模块里没有的函数。如下:
函数 | 描述 |
start() | 开始线程的执行 |
run() | 定义线程的功能的函数(一般会被子类重写) |
join(timeout=None) | 程序挂起,直到线程结束;如果给了timeout,则最多阻塞timeout秒 |
getName() | 返回线程的名字 |
setName(name) | 设置线程的名字 |
isAlive() | 布尔标志,表示这个线程是否还在运行中 |
isDaemon() | 返回线程的daemon标志 |
setDaemon(daemonic) | 把线程的daemon标志设为daemonic(一定要在start函数前调用) |
1)创建一个Thread的实例,传递它一个函数;
2)创建一个Thread的实例,传递它一个可调用的类对象;
3)从Thread派生出一个子类,创建一个这个子类的实例。
1).创建一个Thread实例,传给它一个函数
import threading
import time
loops=[4,2]
def loop(nloop,nsesc):
print 'start loop:',nloop,'at:',time.ctime()
time.sleep(nsesc)
print 'loop:',nloop,'done at:',time.ctime()
def main():
print 'starting at:',time.ctime()
threads=[]
nloops=range(len(loops))
for i in nloops:
t=threading.Thread(target=loop,args=(i,loops[i]))
threads.append(t)
print t.getName()
for j in nloops: #start threads
threads[j].start()
for k in nloops: #wait for all
threads[k].join() #threads to finish
print 'done at:',time.ctime()
if __name__ == '__main__':
main()
starting at: Wed Sep 13 09:40:13 2017
Thread-1
Thread-2
start loop: 0 at: Wed Sep 13 09:40:13 2017
start loop: 1 at: Wed Sep 13 09:40:13 2017
loop: 1 done at: Wed Sep 13 09:40:15 2017
loop: 0 done at: Wed Sep 13 09:40:17 2017
done at: Wed Sep 13 09:40:17 2017
实例化一个Thread(调用 Thread())与调用thread.start_new_thread()之间最大的区别就是,新的线程不会立即开始。
在创建线程对象,但不想马上开始运行线程的时候,这是一个很有用的同步特性。所有的线程都创建了之后,再一起
调用 start()函数启动,而不是创建一个启动一个。而且也不用再管理一堆锁(分配锁、获得锁、释放锁、检查锁的状
态等),只要简单地对每个线程调用join()主线程等待子线程的结束即可。join()还可以设置timeout的参数,即主线程
等到超时为止。
join()的另一个比较重要的方面是它可以完全不用调用,一旦线程启动后,就会一直运行,直到线程的函数结束,退出
为止。如果主线程除了等线程结束外,还有其它的事情要做,那就不用调用 join(),只有在等待线程结束的时候才调用join()。
2).创建一个Thread的实例,传递它一个可调用的类对象
import threading
from time import sleep,ctime
loops=[4,2]
class ThreadFunc(object):
def __init__(self,func,args,name):
self.name=name
self.func=func
self.args=args
def __call__(self):
apply(self.func,self.args)
def loop(nloop,nsec):
print 'start loop ',nloop,'at:',ctime()
sleep(nsec)
print 'loop',nloop,'done at:',ctime()
def main():
print 'starting at:',ctime()
threads=[]
nloops=range(len(loops))
for i in nloops: #create all threads
t=threading.Thread(target=ThreadFunc(loop,(i,loops[i]),loop.__name__))
threads.append(t)
for i in nloops: #start all threads
threads[i].start()
for i in nloops: #wait for complet
threads[i].join()
print 'all done at:',ctime()
if __name__=='__main__':
main()
starting at: Wed Sep 13 11:00:15 2017
start loop 0 at: Wed Sep 13 11:00:15 2017
start loop 1 at: Wed Sep 13 11:00:15 2017
loop 1 done at: Wed Sep 13 11:00:17 2017
loop 0 done at: Wed Sep 13 11:00:19 2017
all done at: Wed Sep 13 11:00:19 2017
与传一个函数很相似的另一个方法是在创建线程的时候,传一个可调用的类的实例供线程启动的时候执行,这是多线程编程
的一个更为面向对象的方法。相对于一个或几个函数来说,类对象里可以使用类的强大的功能。创建新线程的时候,Thread
对象会调用ThreadFunc对象,这时会用到一个特殊函数__call__()。由于已经有了要用的参数,所以就不用再传到Thread()
的构造函数中。由于有一个参数的元组,这时要使用apply()函数或使用self.res = self.func(*self.args)。
3).从Thread派生出一个子类,创建一个这个子类的实例
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 getResult(self):
return self.res
def run(self):
print 'starting',self.name,'at:',ctime()
self.res=apply(self.func,self.args)
print self.name,'finish at:',ctime()
def loop(nloop,nsec):
print 'start loop ',nloop,'at:',ctime();
sleep(nsec)
print 'loop',nloop,'done at:',ctime()
def main():
print 'starting at:',ctime()
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()
starting at: Wed Sep 13 13:14:32 2017
starting loop at: Wed Sep 13 13:14:32 2017
start loop 0 at:starting Wed Sep 13 13:14:32 2017loop
at: Wed Sep 13 13:14:32 2017
start loop 1 at: Wed Sep 13 13:14:32 2017
loop 1 done at: Wed Sep 13 13:14:34 2017
loop finish at: Wed Sep 13 13:14:34 2017
loop 0 done at: Wed Sep 13 13:14:36 2017
loop finish at: Wed Sep 13 13:14:36 2017
all done at: Wed Sep 13 13:14:36 2017
子类化Thread类,MyThread子类的构造函数一定要先调用基类的构造函数,特殊函数__call__()在子类中,名字要改为run()。
在 MyThread类中,加入一些用于调试的输出信息,把代码保存到myThread模块中,并导入这个类。除使用apply()函数来
运行这些函数之外,还可以把结果保存到实现的self.res属性中,并创建一个新的函数getResult()来得到结果。
threading模块中的其他函数
activeCount()
当前活动的前程对象的数量
currentThread()
返回当前线程对象
enumerate()
返回当前活动线程的列表
settrace()
为所有线程设置一个跟踪函数
setprofile()
为所有线程设置一个profile函数