python提供了几个用于多线程编程的模块,包括thread,threading和Queue,前两个模块允许程序员创建和管理线程。thread模块提供了基本的线程和锁的支持,而threading提供了更高级,功能更强的线程管理功能。Queue模块允许用户创建一个可以用于多个线程之间共享数据的队列的数据结构。
thread模块
thread模块提供了基本了生产线程的函数也提供了基本的同步数据结构的锁对象(look object)
先来看一个单线程的程序(假设loop0()和loop1()里做的不是睡眠而是各自独立的,不想关的运算):
</pre><pre name="code" class="python">from time import sleep, ctime
def loop0():
print 'start loop 0 at:', ctime()
sleep(4)
print 'loop 0 done at:', ctime()
def loop1():
print 'start loop 1 at:', ctime()
sleep(2)
print 'loop 1 done at:', ctime()
def main():
print 'starting at:', ctime()
loop0()
loop1()
print 'all DONE at:', ctime()
if __name__ == '__main__':
main()
当我们使用Thread提供的多线程机制时,两个线程能够并发的执行
import thread
from time import sleep, ctime
def loop0():
print 'start loop 0 at:', ctime()
sleep(4)
print 'loop 0 done at:', ctime()
def loop1():
print 'start loop 1 at:', ctime()
sleep(2)
print 'loop 1 done at:', ctime()
def main():
print 'starting at:', ctime()
thread.start_new_thread(loop0, ())
thread.start_new_thread(loop1, ())
sleep(6)
print 'all DONE at:', ctime()
if __name__ == '__main__':
main()
其运行结果如下
starting at: Thu Jul 2 16:16:57 2015
start loop 0 at: Thu Jul 2 16:16:57 2015
start loop 1 at: Thu Jul 2 16:16:57 2015
loop 1 done at: Thu Jul 2 16:16:59 2015
loop 0 done at: Thu Jul 2 16:17:01 2015
all DONE at: Thu Jul 2 16:17:03 2015
其中sleep(6)是为了让主线程停下来,不然loop1(),loop0()还没有开始运行主程序就已经运行到“all done”。
在这里我们使用的是sleep()勉强实现了同步但是程序的总体运行时间并没有减少,更改程序,我们也可以使用锁来实现:
import thread
from time import sleep, ctime
loops = [4, 2]
def loop(nloop, nsec, lock):
print 'start loop', nloop, 'at:', ctime()
sleep(nsec)
print 'loop', nloop, 'done at:', ctime()
lock.release() #每个loop事先被分配了一个锁,在睡眠时间完成后,释放相应的锁以通知主线程
def main():
print 'starting threads...'
locks = []
nloops = range(len(loops))
for i in nloops:
lock = thread.allocate_lock()#创建锁列表
lock.acquire()#获取锁,表示把锁关上
locks.append(lock)#放入锁列表
for i in nloops:#创建线程
thread.start_new_thread(loop,
(i, loops[i], locks[i]))
for i in nloops:#暂停主线程,直到两个锁都被解锁
while locks[i].locked(): pass
print 'all DONE at:', ctime()
if __name__ == '__main__':#只有在直接运行这个脚本时才运行主函数
main()
运行结果如下
start loop 1 start loop 0 at:at: Thu Jul 2 16:39:34 2015
Thu Jul 2 16:39:34 2015
loop 1 done at: Thu Jul 2 16:39:36 2015
loop 0 done at: Thu Jul 2 16:39:38 2015
all DONE at: Thu Jul 2 16:39:38 2015
threading模块
threading模块支持守护线程,守护线程一般是一个等待客户请求服务的服务器,如果没有客户提出请求,它就在那儿等着,如果你设定一个线程为守护线程,就表示你在说这个线程是不重要的,在进程退出的时候不用等待这个线程退出,此时可以设定这些线程的daemon属性(在线程开始之前setDaemon()函数为True),如果你要等待子线程完成再退出,那就什么也不做,或者显式的调用setDaemon(False)以保证其daemon
Thread类
用Thread类你有多种方法来创建线程:
1.创建一个Thread实例,传给它一个函数;
2.创建一个Thread实例,传给它一个可调用的类对象;
3.从Thread派生出一个子类,创建一个这个子类的实例;
Thread的函数
创建一个Thread实例,传给它一个函数
import threading
from time import sleep, ctime
loops = [ 4, 2 ]
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 = threading.Thread(target=loop,
args=(i, loops[i]))
threads.append(t)
for i in nloops: # start threads
threads[i].start()
for i in nloops: # wait for all
threads[i].join() # threads to finish
print 'all DONE at:', ctime()
if __name__ == '__main__':
main()
创建线程的时候新的线程不会马上开始,只有等到调用start()才会开始执行,join()函数会等待直到线程结束,或者当给了timeout()参数的时候,会等到超时为止。
创建一个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 completion
threads[i].join()
print 'all DONE at:', ctime()
if __name__ == '__main__':
main()
从Thread派生出一个子类,创建一个这个子类的实例
与上一个程序不同的是(1)MyThread子类构造器一定要先调用基类构造器;(2)_call_()在子类中名字要改为run()
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):
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:
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()
可以把myThread单独写成一个模块,以便以后更加通用:
import threading
from time import time, ctime
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, 'finished at:', \
ctime()
除了同步对象和线程外,thread模块还提供了一些函数: