这期内容当中小编将会给大家带来有关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队列
使任务按照某一种特定顺序有条不紊的进行。下面介绍几种常用的队列:
- queue.Queue()
:先进先出
- queue.LifoQueue()
:先进后出
- queue.PriorityQueue
:优先级队列,优先级的值越小,越先执行
下面介绍几种常用的方法:
- get()
:获取item,如果队列已经取空将会卡住。可设置timeout参数,给定一个超时的值,或者设置参数block=False,队列空直接抛异常
- get_nowait()
:b获取item。如果队列取空了,将会直接抛异常
- put()
:放入队列
- empty()
:队列是否为空
- qsize()
:获取队列的item数量
上述就是小编为大家分享的Python多线程的原理是什么了,如果刚好有类似的疑惑,不妨参照上述分析进行理解。如果想知道更多相关知识,欢迎关注亿速云行业资讯频道。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。