一、多线程简单例子
#!user/bin/python
#-*- coding:utf-8 -*-
import threading
from time import ctime,sleep
def fib(x): # 斐波那契数
sleep(0.05)
if x<2: return 1
return (fib(x-2)+fib(x-1))
def fac(x): # 阶乘
sleep(0.3)
if x<2 :return 1
return x*fac(x-1)
def sum(x): # 累加
sleep(0.3)
if x<2: return 1
return (x+sum(x-1))
n = 10
nfunc1 = [fib,fac,sum]
if __name__ == '__main__':
print "单线程程序开始时间:",ctime()
fib(n)
fac(n)
sum(n)
print"单线程程序结束时间:",ctime()
threads = []
print "多线程程序开始时间:", ctime()
t = threading.Thread(target=fib,args=(n,)) # 实例化线程
threads.append(t)
t = threading.Thread(target=fac,args=(n,))
threads.append(t)
t = threading.Thread(target=sum, args=(n,))
threads.append(t)
nfunc = range(len(nfunc1))
for i in nfunc:
threads[i].start()
for i in nfunc:
threads[i].join()
print"多线程程序结束时间:", ctime()
运行结果:
从运行结果看,多线程在解决问题的效率远高于单线程。
二、基本概念
进程:是一个执行中的程序。
线程:是在同一个进程下执行的程序,并共享相同的上下文。
多线程编程:子任务相互独立,没有因果关系(各个子任务的结果并不影响其他子任务的结果)
特点:本质上是异步的;需要多个并发活动;每个活动的处理顺序是随机的;
让步:线程有一个指令指针,用于记录当前运行的上下文。当其他线程运行时,它可以被抢断(中断)或者临时挂起(也称为睡眠),这种做法叫做让步。
竞态条件(race condition):一个进程中的各个线程和主线程共享同一片数据空间。如果两个或者多个线程访问同一片数据,由于数据访问的顺序不同,可能导致结果不一致。这种情况成为竞态条件。
同步原语:大多数线程库都有一些同步原语,以允许线程管理器控制执行和访问。
主线程的作用:负责了解每个单独线程的任务、数据参数,及这些线程执行完成后会提供什么结果。主线程通过收集每个线程的结果,汇总成一个有意义的结果。
三、thread 模块
案例代码:
#!user/bin/python
#-*- coding:utf-8 -*-
import thread
from time import ctime,sleep
def loop1():
print"start loop1 time at:",ctime()
sleep(4)
print"loop1 done at:",ctime()
def loop2():
print"start loop2 time at:",ctime()
sleep(2)
print"loop2 done at:",ctime()
if __name__=="__main__":
print"The program start time is:",ctime()
thread.start_new_thread(loop1,())
#开始一个线程,参数包括函数(对象)、函数的参数以及可选的关键字参数,即使要执行的函数没有参数,也要传递一个空的元组
thread.start_new_thread(loop2,())
sleep(6)
print"The program is done at:",ctime()
thread 模块提供了基本的线程和锁定支持;thread 模块的核心函数:start_new_thread();该函数包括函数(对象),函数参数和可选的关键字参数;
注意: 即使要执行的函数不需要参数,也要传递一个空的元组。
在该应用程序中加入了sleep(6),因为如果不阻止主线程继续执行,它将直接执行 print”The program is done at:”,ctime(),然后退出,loop1() 和 loop2( ) 两个线程也将直接终止。但是,在实际的应用中,子线程往往有不同的执行时间且时间未知,单纯使用sleep 函数可能过早或者过晚的退出主程序。而锁就可以解决这类问题。
使用线程和锁的例子:
#!user/bin/python
#-*- coding:utf-8 -*-
import thread
from time import ctime,sleep
loops = [4,2]
def loop(nloop,nsec,lock):
print"the loop",nloop," start at:",ctime()
sleep(nsec)
print"the loop ",nloop," done at:",ctime()
lock.release() # 释放锁
if __name__=="__main__":
print"the Program is starting at:",ctime()
locks = []
nloops =range(len(loops))
for i in nloops:
lock = thread.allocate_lock() # 分配LockType 锁对象
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 # 如果获取了锁对象则返回为True, 否则返回 False
print"the Program have done at:",ctime()
每个线程被分配一个以获得的锁。当sleep时间到了,释放对应的锁,向主线程表明该线程已完成。
thread.allocate_lock() 函数用于分配LockType 锁对象
locks.acquire() 函数用于尝试获取锁, 相当于把锁锁上
locks.locked() 每个线程执行完会释放自己的锁对象,该函数用于获取了释放的锁对象,若获取了锁对象则返回True,否则返回False。
exit() 给线程退出指令;
release() 释放锁
为什么不在上锁时启动线程:1、这里打算同步线程;2、获取锁需要一些时间,如果执行太快,可能会出现获取锁之前线程就执行结束的情况。
thread 模块缺点:
它对于进程何时退出没有控制。在主线程退出后,所有的其他线程也会被强制结束,不会发出警告或者适当的清理;
四、threading 模块
守护线程:可用于解决当主线程退出,所有子线程都将终止的问题。
threading 模块的 Thread 类是主要的执行对象,它具有thread 模块中没有的很多函数。
使用 Thread 类用于创建线程,有以下三种方法;
1、创建Thread 的实例,传递给一个函数;
2、创建Thread 的实例,传递给一个可调用的类实例;
3、派生Thread 的子类,并创建子类的实例;
创建Thread 的实例,传递给一个函数
#!user/bin/python
#-*- coding:utf-8 -*-
# 创建一个Thread 的实例,传给他一个函数
import threading
from time import ctime,sleep
loops = [2,4]
def loop(nloop,nsec):
print"start loop",nloop," time at:",ctime()
sleep(nsec)
print"loop",nloop," done at:",ctime()
if __name__=="__main__":
print"The program start time is:",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: # 开始线程
threads[i].start()
for i in nloops: #等待线程结束
threads[i].join() # join 方法,让主线程等待所有线程执行完毕
print"The program is done:",ctime()
实例化Thread(调用Thread())和调用 thread.start_new_thread() 最大的区别是:前者线程不会立即开始执行;当不希望线程立即开始时,这是一个很有用的同步功能。
当所有线程分配完成后,调用每个线程的 start() 方法开始执行;join() 方法成为自旋锁,作用是将等待线程结束;
join(timeout = None),直至启动线程终止前一直挂起;除非给定了timeout(秒),否则一直处于阻塞状态。
创建Thread 的实例,传递给一个可调用的类实例
这种方法的好处是:这个类更加通用,而不局限与loop 函数,最后一个例子给出说明。
#!user/bin/python
#-*- coding:utf-8 -*-
# 创建一个Thread 的实例,传给它一个可调用的类实例
import threading
from time import ctime,sleep
loops = [4,2]
# 这个类更加通用,而不局限与loop 函数。让类保存了函数的参数、函数自身、函数名的字符串
class ThreadFunc(object):
def __init__(self,func,args,name=""):
self.name = name
self.func = func
self.args = args
def __call__(self): #创建新线程时,Thread 类的代码将调用T和ThreadFunc 的对象,此时会调用__call__() 这个特殊方法
self.func(*self.args)
def loop(nloop,nsec):
print"start loop:",nloop,"at:",ctime()
sleep(nsec)
print"nloop",nloop,"is done at:",ctime()
if __name__ == "__main__":
print"The program start time is:", ctime()
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()
for i in nloops: # 等待线程结束
threads[i].join() # join 方法,让主线程等待所有线程执行完毕
print"The program is done:", ctime()
派生 Thread 的子类,并创建子类的实例
#!user/bin/python
#-*- coding:utf-8 -*-
# 将 Thread 子类化,而不是直接将其实例化
import threading
from time import ctime,sleep
loops = [4,2]
class MyThreadFunc(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"The program",self.name," start time is:",ctime()
self.res = self.func(*self.args)
print"The program",self.name,"have done at:",ctime()
def loop(nloop,nsec):
print"start loop:",nloop,"at:",ctime()
sleep(nsec)
print"nloop",nloop,"is done at:",ctime()
if __name__ == "__main__":
print"The program start time is:", ctime()
threads = []
nloops = range(len(loops))
for i in nloops:
t = MyThreadFunc(loop,(i,loops[i]),loop.__name__)
threads.append(t)
for i in nloops: # 开始线程
threads[i].start()
for i in nloops: # 等待线程结束
threads[i].join() # join 方法,让主线程等待所有线程执行完毕
print"The program is done:", ctime()
注意:1、MyThread 子类的构造函数必须先调用其基类的构造函数‘2、子类中必须有 run() 这个特殊方法。
使用案例:
#!user/bin/python
#-*- coding:utf-8 -*-
# 创建一个Thread 的实例,传给它一个可调用的类实例
import threading
from time import ctime,sleep
from EX4 import MyThreadFunc
from time import ctime,sleep
def fib(x): # 斐波那契数
sleep(0.005)
if x<2: return 1
return (fib(x-2)+fib(x-1))
def fac(x): # 阶乘
sleep(0.1)
if x<2 :return 1
return x*fac(x-1)
def sum(x): # 累加
sleep(0.1)
if x<2: return 1
return (x+sum(x-1))
funcs = [fib,fac,sum]
n = 12
if __name__ == '__main__':
nfunc = range(len(funcs))
threads = []
print "单线程程序开始时间:",ctime()
print"fib 计算结果为:", fib(n)
print"fac 计算结果为:",fac(n)
print"sum 计算结果为:",sum(n)
print"单线程程序结束时间:",ctime()
print "多线程程序开始时间:", ctime()
for i in nfunc:
t = MyThreadFunc(funcs[i],(n,),funcs[i].__name__)
threads.append(t)
for i in nfunc:
threads[i].start()
for i in nfunc:
threads[i].join()
print threads[i].getResult() # 打印计算结果
print"The program have done:"
print"多线程程序结束时间:", ctime()
——摘自《Python 核心编程》