这期内容当中小编将会给大家带来有关Python多线程的原理是什么,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。
Python主要用来做什么
Python主要应用于:1、Web开发;2、数据科学研究;3、网络爬虫;4、嵌入式应用开发;5、游戏开发;6、桌面应用开发。
创建并启动一个线程
import threading
def runtask(name):
print("%s线程已启动"%name)
t = threading.Thread(target=runtask,args=("task1",)) # args因为是一个元组,所以必须这样写,否则运行将报错
t.start()
join
等待当前线程执行完毕
import threading
import time
def runtask(name):
print("%s线程已启动"%name)
time.sleep(2)
t = threading.Thread(target=runtask,args=("task1",))
t.start()
t.join()
print("abc") # 过了2s才会打印,若无等待将看不到等待2s的效果
setDaemon(True)
将线程设置为守护线程。若设置为守护线程,主线程结束后,子线程也将结束,并且主线程不会理会子线程是否结束,主线程不会等待子线程结束完后才结束。若没有设置为守护线程,主线程会等待子线程结束后才会结束。
active_count
程序的线程数量,数量=主线程+子线程数量
Lock(互斥锁)
Python编程中,引入了对象互斥锁的概念,来保证共享数据操作的完整性。每个对象都对应于一个可称为” 互斥锁” 的标记,这个标记用来保证在任一时刻,只能有一个线程访问该对象。在Python中我们使用threading模块提供的Lock类。
import threading,time
def runtask(name):
global count
time.sleep(1)
lock.acquire() # 获取锁资源,并返回是否获取成功
count+=1
print(name,count)
lock.release() # 释放资源
count = 0
lock = threading.Lock() # 互斥锁
for index in range(50):
t = threading.Thread(target=runtask,args=("thread%d"%index,))
t.start()
上面这段代码如果没有加上互斥锁,在Python2.x中执行的结果将会是乱的。在Python3.x中执行却总是正确的,似乎是自动为其加了锁
RLock(递归锁,可重入锁)
当一个线程中遇到锁嵌套情况该怎么办,又会遇到什么情况?
def run1():
global count1
lock.acquire()
count1 += 1
lock.release()
return count1
def run2():
global count2
lock.acquire()
count2 += 1
lock.release()
return count2
def runtask():
lock.acquire()
r1 = run1()
print("="*30)
r2 = run2()
lock.release()
print(r1,r2)
count1,count2 = 0,0
lock = threading.Lock()
for index in range(50):
t = threading.Thread(target=runtask,)
t.start()
这是一个很简单的线程锁死案例,程序将被卡死,停止不动。为了解决这一情况,Python提供了递归锁RLock(可重入锁)。这个RLock内部维护着一个Lock和一个counter变量,counter记录了acquire的次数,从而使得资源可以被多次require。直到一个线程所有的acquire都被release,其他的线程才能获得资源。上面的代码只需做一些小小的改动
lock = threading.Lock()
修改为:
lock = threading.RLock()
那么程序将不会发生死锁情况。
最大可执行线程
threading.BoundedSemaphore(5)
设置可同时执行的最大线程数为5个,后面的线程需排队等待前面的线程执行完毕
import time,threading
def runtask(name):
global num
semaphore.acquire()
time.sleep(1)
num += 1
semaphore.release()
print(name,num)
num = 0
semaphore = threading.BoundedSemaphore(5)
for index in range(50):
t = threading.Thread(target=runtask,args=("线程%s"%index,))
t.start()
执行效果:
可以看出上面的程序是每次只有5个线程在同时运行,其他线程需等待前面的线程执行完毕,这就是最大可执行线程。
Event
Python提供了Event对象用于线程间通信,它是由线程设置的信号标志,如果信号标志位为假,则线程等待直到信号被其他线程设置成真。Event中提供了四个重要的方法来满足基本的需求。
- clear:清除标记
- set:设置标记
- is_set:是否被标记
- wait:等待被标记
代码示例:
import threading,time
def lighter():
num = 0
event.set() # 设置标记
while True:
if num >= 5 and num < 10:
event.clear() # 清除标记
print("红灯亮起,车辆禁止通行")
if num >= 10:
event.set() # 设置标记
print("绿灯亮起,车辆可以通行")
num = 0
num += 1
time.sleep(1)
def car():
while True:
if event.is_set():
print("车辆正在跑...")
else:
print("车辆停下了")
event.wait()
time.sleep(1)
event = threading.Event()
t1 = threading.Thread(target=lighter,)
t2 = threading.Thread(target=car,)
t1.start()
t2.start()
这是一个简单的红灯停绿灯行案例。初始设置为绿灯并标记,车辆看到标记后通行,当红灯亮起的时候取消标记,车辆看到没有标记时停下,等待标记。
Queue队列
使任务按照某一种特定顺序有条不紊的进行。下面介绍几种常用的队列:
下面介绍几种常用的方法:
- get()
:获取item,如果队列已经取空将会卡住。可设置timeout参数,给定一个超时的值,或者设置参数block=False,队列空直接抛异常
- get_nowait()
:b获取item。如果队列取空了,将会直接抛异常
- put()
:放入队列
- empty()
:队列是否为空
- qsize()
:获取队列的item数量
上述就是小编为大家分享的Python多线程的原理是什么了,如果刚好有类似的疑惑,不妨参照上述分析进行理解。如果想知道更多相关知识,欢迎关注天达云行业资讯频道。