Python学习心得(七) 深入理解threading多线程模块

时间:2022-07-08 16:25:02

  Python提供了多个模块来支持多线程编程,包括thread、threading和queue模块等。
thread模块提供了基本的线程和锁定支持;而threading模块提供了更高级别、功能更全面的线程管理。
queue模块,用户可以创建一个队列数据结构,用于在多线程之间进行共享。

核心提示:避免使用thread模块
推荐使用更高级别的threading模块,原因如下:
1.threading模块更加先进,有更好的线程支持,并且thread模块中的一些属性会和threading模块有冲突;
2.低级别的thread模块拥有的同步原语很少(实际上只有一个),而threading模块则有很多;
3.thread模块对于进程何时退出没有控制,当主线程结束时,所有其他线程也都强制结束,不会发出警告或者进行适当的清理;
4.threading模块至少能确保重要的子线程在进程退出去前结束。
5.thread模块不支持守护线程这个概念(thread:当主线程退出时,所有子线程都将终止,不管它们是否仍在工作)

 

一.避免使用thread模块,但要了解其基本用法

import thread 
from time import sleep,ctime,strftime

loops = [4,2]

def loop(nloop,nsec,lock):
print 'start loop',nloop,'at:',strftime('%Y-%m-%d %H:%M:%S')
sleep(nsec)
print 'loop',nloop,'done,at:',strftime('%Y-%m-%d %H:%M:%S')
lock.release() #释放锁
def main():
print 'starting at:',strftime('%Y-%m-%d %H:%M:%S')
locks = []
nloops = range(len(loops)) #[0, 1]
for i in nloops:
lock = thread.allocate_lock() #获取LockType锁对象
lock.acquire() #取得每个锁(相当于"把锁锁上")
locks.append(lock) #一旦锁被锁上,就可以把它添加到锁列表locks中了
#print locks
for i in nloops: #派生线程
#每个线程会调用loop()函数,并传递循环号、睡眠时间以及用于该线程的锁
thread.start_new_thread(loop,(i,loops[i],locks[i]))
sleep(1)
for i in nloops:
while locks[i].locked(): #暂停主线程,等待,直到所有锁都被释放之后才会继续执行
pass
print 'all done at:',strftime('%Y-%m-%d %H:%M:%S')

if __name__ == '__main__':
main()

二.推荐使用更高级别的threading模块,函数式编程法  

import threading
#threading模块的Thread类有一个join()方法,可以让主线程等待所有线程执行完毕

from time import sleep,strftime

loops = [4,2,2]

def loop(nloop,nsec):
print 'start loop',nloop,'at:',strftime('%Y-%m-%d %H:%M:%S')
sleep(nsec)
print 'loop',nloop,'done,at:',strftime('%Y-%m-%d %H:%M:%S')
def main():
print 'starting at:',strftime('%Y-%m-%d %H:%M:%S')
threads = []
nloops = range(len(loops)) #[0, 1]

for i in nloops:
#实例化Thread(调用Thread()和之前调用thread.start_new_thread()最大区别在于新线程不会立即开始执行
t = threading.Thread(target=loop,args=(i,loops[i])) #这是个非常有用的同步功能
threads.append(t)

for i in nloops: #启动线程
#当所有线程都分配完成后,通过调用每个线程的start()方法来让它们执行,而不是在这之前就会执行
threads[i].start()

for i in nloops:
#为每个线程调用join()方法,join()方法将等待线程结束,或在提供了超时时间的情况下,达到超时时间。
threads[i].join()
#join()方法只有在你需要等待线程完成的时候才有用
#join()方法其实根本不需要调用,一旦线程启动,它们就会一直执行,直到给定的函数完成后退出。

print 'all done at:',strftime('%Y-%m-%d %H:%M:%S')

print loop.__name__

if __name__ == '__main__':
main()

三.threading模块的面向对象编程法,使用可调用的类 

import threading
from time import sleep,strftime

loops = [4,2]

class ThreadFunc(object): #添加ThreadFunc类
def __init__(self,func,args,name = ''): #构造方法设定函数自身,函数参数及函数名的字符串
self.name = name
self.func = func
self.args = args
def __call__(self): #__call__特殊方法直接调用
self.func(*self.args)

def loop(nloop,nsec):
print 'start loop',nloop,'at:',strftime('%Y-%m-%d %H:%M:%S')
sleep(nsec)
print 'loop',nloop,'done at:',strftime('%Y-%m-%d %H:%M:%S')

def main():
print 'starting at:',strftime('%Y-%m-%d %H:%M:%S')
threads = []
nloops = range(len(loops))

for i in nloops: #实例化Thread类对象
t = threading.Thread(target=ThreadFunc(loop,(i,loops[i]),loop.__name__)) #分配线程
threads.append(t)

for i in nloops:
threads[i].start() #真正通过start()方法才启动线程


for i in nloops:
threads[i].join() #等待线程完成
print 'all done at:',strftime('%Y-%m-%d %H:%M:%S')

if __name__ == '__main__':
main()

四.threading模块面向对象扩展,派生Thread的子类,并创建子类的实例 

'''
import threading
from time import sleep,strftime

loops = [4,2]

class MyThread(threading.Thread):
def __init__(self,func,args,name=''):
threading.Thread.__init__(self) #MyThread子类的构造方法必须先调用基类(即父类)的构造方法
self.name = name
self.func = func
self.args = args

def run(self): #之前的特殊方法__call__在这里必须要写成run()
self.func(*self.args)

def loop(nloop,nsec):
print 'start loop',nloop,'at:',strftime('%Y-%m-%d %H:%M:%S')
sleep(nsec)
print 'loop',nloop,'done at:',strftime('%Y-%m-%d %H:%M:%S')

def main():
print 'starting at:',strftime('%Y-%m-%d %H:%M:%S')
threads = []
nloops = range(len(loops))
#print nloops

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:',strftime('%Y-%m-%d %H:%M:%S')

if __name__ == '__main__':
main()

'''

#Thread子类MyThread
#将上面的代码独立作为一个模块,把结果保存在实例属性self.res中,并创建一个新的方法getResult()来获取这个值

import threading
from time import strftime

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:',strftime('%Y-%m-%d %H:%M:%S')
self.res = self.func(*self.args)
print self.name,'finished at:',strftime('%Y-%m-%d %H:%M:%S')

  

参考资料《python核心编程》(第3版)