Python 多线程编程(thread 模块)
thread 模块
让我们先来看看thread 模块提供了什么。除了派生线程外,thread 模块还提供了基本的
同步数据结构,称为锁对象(lock object,也叫原语锁、简单锁、互斥锁、互斥和二进制信号
量)。如前所述,这个同步原语和线程管理是密切相关的。
表4-1 列出了一些常用的线程函数,以及LockType 锁对象的方法。
thread 模块的核心函数是start_new_thread()。它的参数包括函数(对象)、函数的参数以
及可选的关键字参数。将专门派生新的线程来调用这个函数。
把多线程整合进onethr.py 这个例子中。把对loop*()函数的调用稍微改变一下,得到示例
4-2 中的mtsleepA.py 文件。

import thread
from concurrent.futures 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('loop1 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()
start_new_thread()必须包含开始的两个参数,于是即使要执行的函数不需要参数,也需
要传递一个空元组。
与之前的代码相比,本程序执行后的输出结果有很大不同。原来需要运行6~7 秒的时间,
而现在的脚本只需要运行4 秒,也就是最长的循环加上其他所有开销的时间之和。
$ mtsleepA.py
starting at: Sun Aug 13 05:04:50 2006
start loop 0 at: Sun Aug 13 05:04:50 2006
start loop 1 at: Sun Aug 13 05:04:50 2006
loop 1 done at: Sun Aug 13 05:04:52 2006
loop 0 done at: Sun Aug 13 05:04:54 2006
al l DONE at: Sun Aug 13 05:04:56 2006
睡眠4 秒和睡眠2 秒的代码片段是并发执行的,这样有助于减少整体的运行时间。你甚
至可以看到loop 1 是如何在loop 0 之前结束的。
这个应用程序中剩下的一个主要区别是增加了一个sleep(6)调用。为什么必须要这样做
呢?这是因为如果我们没有阻止主线程继续执行,它将会继续执行下一条语句,显示“all
done”然后退出,而loop0()和loop1()这两个线程将直接终止。
我们没有写让主线程等待子线程全部完成后再继续的代码,即我们所说的线程需要某种
形式的同步。在这个例子中,调用sleep()来作为同步机制。将其值设定为6 秒是因为我们知
道所有线程(用时4 秒和2 秒的)会在主线程计时到6 秒之前完成。
你可能会想到,肯定会有比在主线程中额外延时6 秒更好的线程管理方式。由于这个延
时,整个程序的运行时间并没有比单线程的版本更快。像这样使用sleep()来进行线程同步是
不可靠的。如果循环有独立且不同的执行时间要怎么办呢?我们可能会过早或过晚退出主线
程。这就是引出锁的原因。
再一次修改代码,引入锁,并去除单独的循环函数,修改后的代码为mtsleepB.py,如示
例4-3 所示。我们可以看到输出结果与mtsleepA.py 相似。唯一的区别是我们不需要再像
mtsleepA.py 那样等待额外的时间后才能结束。通过使用锁,我们可以在所有线程全部完成执
行后立即退出。其输出结果如下所示。
$ mtsleepB.py
starting at: Sun Aug 13 16:34:41 2006
start loop 0 at: Sun Aug 13 16:34:41 2006
start loop 1 at: Sun Aug 13 16:34:41 2006
loop 1 done at: Sun Aug 13 16:34:43 2006
loop 0 done at: Sun Aug 13 16:34:45 2006
al l DONE at: Sun Aug 13 16:34:45 2006
那么我们是如何使用锁来完成任务的呢?下面详细分析源代码。
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()
def main():
print('starting at:',ctime())
locks=[]
nloops=range(len(loops))
for i in nloops:
lock=thread.allocate_lock()
lock.aquire()
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()
更多推荐



所有评论(0)