Python中互斥锁、递归锁、信号量、事件如何实现多线程同步?

2026-05-26 21:461阅读0评论SEO教程
  • 内容介绍
  • 文章标签
  • 相关推荐

本文共计2344个文字,预计阅读时间需要10分钟。

Python中互斥锁、递归锁、信号量、事件如何实现多线程同步?

原文:本文实例讲述了Python多线程操作之互斥锁、递归锁、信号量、事件。

分享给大众提供参考,具体如下:

互斥锁:为什么要有互斥锁:由于多线程是并行的,如果多个线程同时访问同一资源,可能会导致数据不一致。互斥锁可以保证同一时间只有一个线程可以访问该资源。

递归锁:递归锁是互斥锁的一种,允许同一个线程多次获取锁。

信号量:信号量用于控制多个线程对资源的访问数量。

事件:事件用于线程间的同步,当事件被设置时,等待该事件的线程会被唤醒。

改写后:本文以实例说明Python多线程操作中的互斥锁、递归锁、信号量和事件。

以下内容供大家参考:

互斥锁:为何需要互斥锁:多线程并行执行时,若多个线程同时访问同一资源,可能导致数据不一致。互斥锁确保同一资源在同一时间仅被一个线程访问。

递归锁:递归锁是互斥锁的变种,允许同一线程多次获取同一锁。

信号量:信号量用于限制对资源的并发访问数量。

事件:事件用于线程同步,当事件被触发时,等待该事件的线程将被唤醒。

本文实例讲述了Python多线程操作之互斥锁、递归锁、信号量、事件。分享给大家供大家参考,具体如下:

互斥锁:

  • 为什么要有互斥锁:由于多线程是并行的,如果某一线程取出了某一个数据将要进行操作,但它还没有那么快执行完操作,这时候如果另外一个线程也要操作这个数据,那么这个数据可能会因为两次操作而发生错误

import time,threading x=6 def run1(): print("run1我拿到了数据:",x) print("我现在还不想操作,先睡一下") time.sleep(3) print("再看一下数据,稳一稳",x) def run2(): global x print("run2我拿到了数据:", x) x=5 print(x) t1=threading.Thread(target=run1) t2=threading.Thread(target=run2) t1.start() t2.start() t1.join() t2.join()

  • 而多线程的互斥锁机制本质上是:申请一个锁,A线程拿了钥匙之后,如果B也想拿到钥匙是不行的,只有等A把钥匙还回来才行
  • 如何使用互斥锁:
    1. 定义一个锁对象:锁对象=threading.Lock()
    2. 请求锁:锁对象.acquire()
    3. 释放锁:锁对象.release()

使用互斥锁来更改上段代码

import time,threading x=6 def run1(): lock.acquire() global x print("run1我拿到了数据,x=",x) print("我现在还不想操作,先睡一下") time.sleep(3) print("再看一下数据,稳一稳,x=",x) x+=1 print("run1操作完毕:x=",x) lock.release() def run2(): lock.acquire() global x print("run2我拿到了数据:", x) x+=1 print("run2操作完毕:x=",x) lock.release() lock=threading.Lock()#生成一个锁对象 t1=threading.Thread(target=run1) t2=threading.Thread(target=run2) t1.start() t2.start() start_time=time.time() t1.join() t2.join() print("最终的x=",x) print(time.time()-start_time)#3.0多说明,由于受到锁的影响,run2要等待run1释放lock,所以变成了串行

这种互斥锁在操作系统中可以称作“临界区”,如果想了解更多:

baike.baidu.com/item/%E4%B8%B4%E7%95%8C%E5%8C%BA/8942134?fr=aladdin


递归锁:

  • 为什么要有递归锁:互斥锁本质上是阻止其他线程进入,如果有两个需要阻止其他线程进入的操作,那么需要两个锁,而想要锁上第二个如果直接用第一个锁的acquire会失败,因为第一个锁还没release,我们可以选择再定义一个互斥锁对象来acquire,但这仅仅是两层的情况下,如果多层的吧,那么就需要定义好几个互斥锁对象了。递归锁就是为了处理这种情况,递归锁对象允许多次acquire和多次release
    • 发生死锁的情况[A拿到A锁,想要拿B锁,B拿着B锁,想要A锁]

:桥只能容一个人通过,A只能看得到北边桥上有没有人,看不到南边桥有没有人,当他看到北边桥没人就会过桥,等到他到桥中间才能看到南边桥有没有人,B情况相反:

import threading,time """ A只能看得到北边桥上有没有人,看不到南边桥有没有人, 当他看到北边桥没人就会过桥,等到他到桥中间才能看到南边桥有没有人 """ def A(): lockNorth.acquire()#拿到北边桥的锁 print("A过桥北") time.sleep(3)#过桥中 lockSorth.acquire()#企图过到南边桥, print("A过桥南") time.sleep(3) # 过桥中 lockSorth.release() lockNorth.release() print("A过桥成功") """ B只能看得到南边桥上有没有人,看不到北边桥有没有人, 当他看到南边桥没人就会过桥,等到他到桥中间才能看到北边桥有没有人 """ def B(): lockSorth.acquire() # 企图过到南边桥, print("B过桥南") time.sleep(3) # 过桥中 lockNorth.acquire() # 拿到北边桥的锁 print("B过桥北") time.sleep(3) # 过桥中 lockNorth.release() lockSorth.release() print("B过桥成功") lockNorth=threading.Lock() lockSorth=threading.Lock() tA=threading.Thread(target=A) tB=threading.Thread(target=B) tA.start() tB.start() tA.join() tB.join()

  • 递归锁的本质是:本质上还是一个锁,但如果在一个线程里面可以多次acquire。
  • 如何使用递归锁:
    1. 定义一个锁对象:递归锁对象=threading.RLock()
    2. 请求锁:锁对象.acquire()
    3. 释放锁:锁对象.release()

使用递归锁来解决上面的死锁问题:

import threading,time """ A只能看得到北边桥上有没有人,看不到南边桥有没有人, 当他看到北边桥没人就会过桥,等到他到桥中间才能看到南边桥有没有人 """ def A(): lock.acquire()#拿到北边桥的锁 print("A过桥北") time.sleep(3)#过桥中 lock.acquire()#企图过到南边桥, print("A过桥南") time.sleep(3) # 过桥中 lock.release() lock.release() print("A过桥成功") """ B只能看得到南边桥上有没有人,看不到北边桥有没有人, 当他看到南边桥没人就会过桥,等到他到桥中间才能看到北边桥有没有人 """ def B(): lock.acquire() # 拿南桥锁, print("B过桥南") time.sleep(3) # 过桥中 lock.acquire() # 企图拿北桥的锁 print("B过桥北") time.sleep(3) # 过桥中 lock.release() lock.release() print("B过桥成功") lock=threading.RLock() tA=threading.Thread(target=A) tB=threading.Thread(target=B) tA.start() tB.start() tA.join() tB.join()


信号量:

  • 什么是信号量:

信号量可以限制进入的线程的数量。

  • 如何使用信号量:
    1. 创建信号量对象:信号量对象=threading.BoundedSemaphore(x),x是限制进程的数量
    2. 当有进程需要进入的时候,调用acquire()来减少信号量:信号量对象.acquire()
    3. 当有进程离开的时候,调用release()来增加信号量:信号量对象.release()

import threading,time def run(): s.acquire() print("hello") time.sleep(1.5) s.release() s=threading.BoundedSemaphore(3)#限制3个 threading_list=[] for i in range(12):#创建12个线程 obj=threading.Thread(target=run) obj.setDaemon(True) # 设置守护线程,避免干扰主线程运行,并行等待 obj.start() for i in range(4): print("")#为了把结果分割,可以清楚看出分为了三组 time.sleep(1.5) #结果分为三组是因为运行的太快了,三个线程装入的时间差太小


Python中互斥锁、递归锁、信号量、事件如何实现多线程同步?

事件:

  • 什么是事件:当发生线程发生一件事的时候如果要提醒另外一个线程,使用事件。双方共享该事件对象,当一方更改事件对象的时候,另外一方也能知道
  • 如何使用事件:
    1. 创建事件对象:事件对象=threading.Event()
    2. 设置事件:事件对象.set() 判断事件是否set:事件对象.is_set(),等待事件set:事件对象.wait()
    3. 清除事件:事件对象.clear()

import threading,time def read(): while True: if event.is_set(): print("事件已设置,我要读了!!!!") time.sleep(1) else:#事件未设置 print("还没写好,我要等咯") event.wait()#那么就等着咯 #如果等到了 print("终于等到了!那么我又可以读了") time.sleep(1) def write(): event.clear()#初始设空 while True: time.sleep(3)#写 event.set()#设置事件,一旦set,那么读者wait就有返回了,读者可以继续运行了 print("write:写好了") time.sleep(2)#等人读 event.clear()#清除事件 event=threading.Event() #创建事件对象 t1=threading.Thread(target=write) t2=threading.Thread(target=read) t1.start() t2.start() t1.join() t2.join() """结果显示:读者确实一直在等待写者写好"""

更多关于Python相关内容感兴趣的读者可查看本站专题:《Python进程与线程操作技巧总结》、《Python数据结构与算法教程》、《Python函数使用技巧总结》、《Python字符串操作技巧汇总》、《Python入门与进阶经典教程》、《Python+MySQL数据库程序设计入门教程》及《Python常见数据库操作技巧汇总》

希望本文所述对大家Python程序设计有所帮助。

本文共计2344个文字,预计阅读时间需要10分钟。

Python中互斥锁、递归锁、信号量、事件如何实现多线程同步?

原文:本文实例讲述了Python多线程操作之互斥锁、递归锁、信号量、事件。

分享给大众提供参考,具体如下:

互斥锁:为什么要有互斥锁:由于多线程是并行的,如果多个线程同时访问同一资源,可能会导致数据不一致。互斥锁可以保证同一时间只有一个线程可以访问该资源。

递归锁:递归锁是互斥锁的一种,允许同一个线程多次获取锁。

信号量:信号量用于控制多个线程对资源的访问数量。

事件:事件用于线程间的同步,当事件被设置时,等待该事件的线程会被唤醒。

改写后:本文以实例说明Python多线程操作中的互斥锁、递归锁、信号量和事件。

以下内容供大家参考:

互斥锁:为何需要互斥锁:多线程并行执行时,若多个线程同时访问同一资源,可能导致数据不一致。互斥锁确保同一资源在同一时间仅被一个线程访问。

递归锁:递归锁是互斥锁的变种,允许同一线程多次获取同一锁。

信号量:信号量用于限制对资源的并发访问数量。

事件:事件用于线程同步,当事件被触发时,等待该事件的线程将被唤醒。

本文实例讲述了Python多线程操作之互斥锁、递归锁、信号量、事件。分享给大家供大家参考,具体如下:

互斥锁:

  • 为什么要有互斥锁:由于多线程是并行的,如果某一线程取出了某一个数据将要进行操作,但它还没有那么快执行完操作,这时候如果另外一个线程也要操作这个数据,那么这个数据可能会因为两次操作而发生错误

import time,threading x=6 def run1(): print("run1我拿到了数据:",x) print("我现在还不想操作,先睡一下") time.sleep(3) print("再看一下数据,稳一稳",x) def run2(): global x print("run2我拿到了数据:", x) x=5 print(x) t1=threading.Thread(target=run1) t2=threading.Thread(target=run2) t1.start() t2.start() t1.join() t2.join()

  • 而多线程的互斥锁机制本质上是:申请一个锁,A线程拿了钥匙之后,如果B也想拿到钥匙是不行的,只有等A把钥匙还回来才行
  • 如何使用互斥锁:
    1. 定义一个锁对象:锁对象=threading.Lock()
    2. 请求锁:锁对象.acquire()
    3. 释放锁:锁对象.release()

使用互斥锁来更改上段代码

import time,threading x=6 def run1(): lock.acquire() global x print("run1我拿到了数据,x=",x) print("我现在还不想操作,先睡一下") time.sleep(3) print("再看一下数据,稳一稳,x=",x) x+=1 print("run1操作完毕:x=",x) lock.release() def run2(): lock.acquire() global x print("run2我拿到了数据:", x) x+=1 print("run2操作完毕:x=",x) lock.release() lock=threading.Lock()#生成一个锁对象 t1=threading.Thread(target=run1) t2=threading.Thread(target=run2) t1.start() t2.start() start_time=time.time() t1.join() t2.join() print("最终的x=",x) print(time.time()-start_time)#3.0多说明,由于受到锁的影响,run2要等待run1释放lock,所以变成了串行

这种互斥锁在操作系统中可以称作“临界区”,如果想了解更多:

baike.baidu.com/item/%E4%B8%B4%E7%95%8C%E5%8C%BA/8942134?fr=aladdin


递归锁:

  • 为什么要有递归锁:互斥锁本质上是阻止其他线程进入,如果有两个需要阻止其他线程进入的操作,那么需要两个锁,而想要锁上第二个如果直接用第一个锁的acquire会失败,因为第一个锁还没release,我们可以选择再定义一个互斥锁对象来acquire,但这仅仅是两层的情况下,如果多层的吧,那么就需要定义好几个互斥锁对象了。递归锁就是为了处理这种情况,递归锁对象允许多次acquire和多次release
    • 发生死锁的情况[A拿到A锁,想要拿B锁,B拿着B锁,想要A锁]

:桥只能容一个人通过,A只能看得到北边桥上有没有人,看不到南边桥有没有人,当他看到北边桥没人就会过桥,等到他到桥中间才能看到南边桥有没有人,B情况相反:

import threading,time """ A只能看得到北边桥上有没有人,看不到南边桥有没有人, 当他看到北边桥没人就会过桥,等到他到桥中间才能看到南边桥有没有人 """ def A(): lockNorth.acquire()#拿到北边桥的锁 print("A过桥北") time.sleep(3)#过桥中 lockSorth.acquire()#企图过到南边桥, print("A过桥南") time.sleep(3) # 过桥中 lockSorth.release() lockNorth.release() print("A过桥成功") """ B只能看得到南边桥上有没有人,看不到北边桥有没有人, 当他看到南边桥没人就会过桥,等到他到桥中间才能看到北边桥有没有人 """ def B(): lockSorth.acquire() # 企图过到南边桥, print("B过桥南") time.sleep(3) # 过桥中 lockNorth.acquire() # 拿到北边桥的锁 print("B过桥北") time.sleep(3) # 过桥中 lockNorth.release() lockSorth.release() print("B过桥成功") lockNorth=threading.Lock() lockSorth=threading.Lock() tA=threading.Thread(target=A) tB=threading.Thread(target=B) tA.start() tB.start() tA.join() tB.join()

  • 递归锁的本质是:本质上还是一个锁,但如果在一个线程里面可以多次acquire。
  • 如何使用递归锁:
    1. 定义一个锁对象:递归锁对象=threading.RLock()
    2. 请求锁:锁对象.acquire()
    3. 释放锁:锁对象.release()

使用递归锁来解决上面的死锁问题:

import threading,time """ A只能看得到北边桥上有没有人,看不到南边桥有没有人, 当他看到北边桥没人就会过桥,等到他到桥中间才能看到南边桥有没有人 """ def A(): lock.acquire()#拿到北边桥的锁 print("A过桥北") time.sleep(3)#过桥中 lock.acquire()#企图过到南边桥, print("A过桥南") time.sleep(3) # 过桥中 lock.release() lock.release() print("A过桥成功") """ B只能看得到南边桥上有没有人,看不到北边桥有没有人, 当他看到南边桥没人就会过桥,等到他到桥中间才能看到北边桥有没有人 """ def B(): lock.acquire() # 拿南桥锁, print("B过桥南") time.sleep(3) # 过桥中 lock.acquire() # 企图拿北桥的锁 print("B过桥北") time.sleep(3) # 过桥中 lock.release() lock.release() print("B过桥成功") lock=threading.RLock() tA=threading.Thread(target=A) tB=threading.Thread(target=B) tA.start() tB.start() tA.join() tB.join()


信号量:

  • 什么是信号量:

信号量可以限制进入的线程的数量。

  • 如何使用信号量:
    1. 创建信号量对象:信号量对象=threading.BoundedSemaphore(x),x是限制进程的数量
    2. 当有进程需要进入的时候,调用acquire()来减少信号量:信号量对象.acquire()
    3. 当有进程离开的时候,调用release()来增加信号量:信号量对象.release()

import threading,time def run(): s.acquire() print("hello") time.sleep(1.5) s.release() s=threading.BoundedSemaphore(3)#限制3个 threading_list=[] for i in range(12):#创建12个线程 obj=threading.Thread(target=run) obj.setDaemon(True) # 设置守护线程,避免干扰主线程运行,并行等待 obj.start() for i in range(4): print("")#为了把结果分割,可以清楚看出分为了三组 time.sleep(1.5) #结果分为三组是因为运行的太快了,三个线程装入的时间差太小


Python中互斥锁、递归锁、信号量、事件如何实现多线程同步?

事件:

  • 什么是事件:当发生线程发生一件事的时候如果要提醒另外一个线程,使用事件。双方共享该事件对象,当一方更改事件对象的时候,另外一方也能知道
  • 如何使用事件:
    1. 创建事件对象:事件对象=threading.Event()
    2. 设置事件:事件对象.set() 判断事件是否set:事件对象.is_set(),等待事件set:事件对象.wait()
    3. 清除事件:事件对象.clear()

import threading,time def read(): while True: if event.is_set(): print("事件已设置,我要读了!!!!") time.sleep(1) else:#事件未设置 print("还没写好,我要等咯") event.wait()#那么就等着咯 #如果等到了 print("终于等到了!那么我又可以读了") time.sleep(1) def write(): event.clear()#初始设空 while True: time.sleep(3)#写 event.set()#设置事件,一旦set,那么读者wait就有返回了,读者可以继续运行了 print("write:写好了") time.sleep(2)#等人读 event.clear()#清除事件 event=threading.Event() #创建事件对象 t1=threading.Thread(target=write) t2=threading.Thread(target=read) t1.start() t2.start() t1.join() t2.join() """结果显示:读者确实一直在等待写者写好"""

更多关于Python相关内容感兴趣的读者可查看本站专题:《Python进程与线程操作技巧总结》、《Python数据结构与算法教程》、《Python函数使用技巧总结》、《Python字符串操作技巧汇总》、《Python入门与进阶经典教程》、《Python+MySQL数据库程序设计入门教程》及《Python常见数据库操作技巧汇总》

希望本文所述对大家Python程序设计有所帮助。