python多线程
一、线程概念
线程是CPU分配资源的基本单位。当一个程序开始运行时,它成为一个过程,一个过程相当于一个或多个线程。当没有多线程编程时,一个过程相当于一个主线程;当有多线程编程时,一个过程包含多个线程(包括主线程)。使用线程可以实现程序的大开发。
可在同一程序中运行多个线程,每个线程完成不同的任务。
多线程实现后台服务程序可以同时处理多个任务,并不发生阻塞现象。
多线程程序设计的特点是提高程序执行效率和处理速度。python多个相对独立的线程可以并行运行。
二、创建多线程
python支持两种创建多线程的方式:
~通过 threading.Thread () 创建。
~通过继承 threading.Thread 类的继承。
1.通过 threading.Thread () 创建
语法形式:
thread.Thread(group=Nore,targt=None,args=(),kwargs={},*,daemon=None)
参数解释:
~group:必须为None,于ThreadGroup一般不使用类相关。
~target:线程调用的对象是目标函数。
~name:给线程起这个名字。Tread-x,x是序号,从1开始,创建的第一个线程名称是Tread-1。
~args:字典将关键字参数传递给目标函数。
~daemon:用于设置线程是否随主线程退出。
示例:
import threading def test (x,y): for i in range(x,y): print(i) thread1 = threading.Thread(name='t1',target= test,args=(1,10)) thread2 = threading.Thread(name='t2',target= test,args=(11,20)) thread1.start() #启动线程1 thread2.start() #启动线程2
输出:
1 2 3 4 5 6 7 8 9 11 12 13 14 15 16 17 18 19
解释:两个程序并发运行,所以结果不一定是每次顺序1~10,这是根据CPU决定两行风马分配的时间片段。每次结果都不一样。
2.通过继承 threading.Thread 类的继承
threading.Thread它是一个可以继承的类别。
示例:
import threading class mythread(threading.Thread): def run(self): for i in range(1,10): print(i) thread1 = mythread(); thread2 = mythread(); thread1.start() thread2.start()
输出:
1 2 3 4 5 6 7 8 9 1 2 3 4 5 6 7 8 9
解释:自定义一类继承threading.Thread,然后重写父类run方法,线程启动(执行)start()该方法将自动执行。
三、主线程
在python主线程是第一个启动线程。
~父线程:如果在启动线程A中启动一个线程B,A是B的父线程。
~子线程:B是a的子线程。
有一个创建线程damon用它来判断主线程的属性。daemon设置False线程不会随着主线程的退出而退出,主线程会等待子线程的执行。daemon设置True当主线程退出时,线程将退出,其他子线程将强制退出。
使用daemon注意:
~daemon属性必须在start( )以前的设置,否则会造成RuntimeError异常
~每个线程都由daemon属性,可以显示设置也可以不设置,不设置默认值None
~若不设置子线程daemon属性取当前线程daemon来设置它。子子线程继承子线程的daemon值、功能和设置None一样。
~不设置从主线程创建的所有线程daemon属性,则默认为daemon=False。
示例:
import time import threading def test(): time.sleep(10) for i in range(10): print(i) thread1 = threading.Thread(target=test,daemon=False) thread1.start() print(主线程完成了)
输出:
主线程完成 0 1 2 3 4 5 6 7 8 9
说明:主线程运行完成输出后,等待输出0~9。如果将daemon=False该为daemon=True,则不会运行for i in range(10)语句。
四、堵塞线程
在另一个线程中调用另一个线程join在调用线程终止之前,方法阻塞了调用器。
语法形式:
join(timeout-=None)
timeout 参数指定调用器等待多久,未设置时等待调用线程结束。其中一个线程可以是join多次调用。
示例:
import time import threading def test(): time.sleep(5) for i in range(10): print(i) thread1=threading.Thread(target=test) thread1.start() thread1.join() print(主线程完成了)
输出:
0 1 2 3 4 5 6 7 8 9 主线程完成
解释:在thread1.start()后加thread1.join()添加join输出时,主线程将等待输出~9后执行自己的print输出。
判断线程是否活动
~run():表示线程活动的方法
~start():启动线程
~join()
~isAlive():返回线程是否活动
~getName():返回线程名称
~setName() : 设置线程名称
示例:
from threading import Thread, Event import time def countdown(n, started_evt): print(正在运行) started_evt.set() while n > 0: print时间, n) n -= 1 time.sleep(2) started_evt = Event() print(开始倒计时) t = Thread(target=countdown, args=(10, started_evt)) t.start() started_evt.wait() print(倒计时操作)
输出:
开始倒计时 正在运行 时间 10 倒计时运行 时间 9 时间 8 时间 7 时间 6 时间 5 时间 4 时间 3 时间 2 时间 1
Alive,顾名思义,它表示线程是否可用。如果线程已经启动,目前没有异常,则返回true,否则为false
Thread.isAlive() :顾名思义,这意味着当前线程处于可用状态,即是否已启动并运行;
六、线程同步
1.同步概念
在异步模式下,一个线程正在修改共享数据,另一个线程正在读取共享数据。当修改后的共享数据线程未完成时,读取数据的线程肯定会得到错误的结果。如果采用多线程同步控制机制,当共享数据的线程完成时,读取线程读取数据。
python锁解决了这个问题,锁定线程,只允许一个线程操作,其他线程排队等待,然后在当前线程操作完成后一个接一个地操作。
2. python的锁
python的threading模块提供了RLock锁定解决方案。只有一个线程操作的句子才能在一定时间内放置RLock的acquire方法和release方法之间,即acquire相当于给RLack上锁,而release相当于解锁。
示例:
import threding
class mythread(threading.Thread):
def run(self):
global x #声明一个全局变量
lock.acquire() #上锁
x +=10
print('%s:%d'%(self.name,x))
lock.release() #解锁
x = 0 #设置全局变量初始值
lock = threading.RLock() #创建可重入锁
list1 = []
for i in range(5):
list1.append(mythread()) #创建五个线程,放到同一列表中
for i in list1:
i.start() #开启列表线程
输出:
Thread-1:10
Thread-2:20
Thread-3:30
Thread-4:40
Thread-5:50
解释:
3. python中的条件锁
条件锁常用的方法:
~acquire([timeout]):调用关联锁的方法
~release():解锁
~wait():使线程进入 Condition 的等待池等待通知并释放解锁。使用前线程必须已获得锁定,否则将抛出异常。
~notify():从等待池挑选一个线程并通知,收到通知的线程将自动调用 acquire() 尝试获得,其他线程仍然在等待池中等待通知,直到该线程收到通知 调用该方法,否则将会抛出异常。
~notify ALL():跟notify() 一样,但这个方法对应的是所有的线程。
示例:
题目:有几个生产车间生产,几个消费者购买,当生产达到一定数量时,停止生产。
import threading
import time
condtion = threading.Condition()
sheep = ['1件产品','1件产品','1件产品','1件产品','1件产品']
class Producer(threading.Thread):
def __init__(self, name):
super().__init__(name=name)
pass
def run(self):
global condtion, sheep
while True:
time.sleep(0.1)
condtion.acquire()
if len(sheep) < 10:
print(self.name + "生产了1件产品")
sheep.append('1件产品')
condtion.notifyAll()
pass
else:
print("仓库满了,停止生产!")
condtion.wait()
pass
condtion.release()
pass
pass
class Customer(threading.Thread):
def __init__(self, name):
super().__init__(name=name)
pass
def run(self):
global condtion, sheep
while True:
time.sleep(0.1)
condtion.acquire()
if len(sheep) > 0:
meat = sheep.pop()
print(self.name + "购买了" + meat + "还剩多少" + str(len(sheep)) + "件")
condtion.notifyAll()
pass
else:
print("买光了,等待")
condtion.wait()
pass
condtion.release()
pass
pass
if __name__ == "__main__":
p1 = Producer("1号生产车间")
p2 = Producer("2号生产车间")
p3 = Producer("3号生产车间")
p4 = Producer("4号生产车间")
p5 = Producer("5号生产车间")
p6 = Producer("6号生产车间")
p1.start()
p2.start()
p4.start()
p5.start()
p6.start()
c1 = Customer('小王')
c2 = Customer('小李')
c3 = Customer('小贾')
c4 = Customer('小沈')
c5 = Customer('小刘')
c1.start()
c2.start()
c3.start()
c4.start()
c5.start()