Python中threading模块 lock、Rlock的使用

简介: Python中threading模块 lock、Rlock的使用

一、概述

在使用多线程的应用下,如何保证线程安全,以及线程之间的同步,或者访问共享变量等问题是十分棘手的问题,也是使用多线程下面临的问题,如果处理不好,会带来较严重的后果,使用python多线程中提供Lock 、Rlock 、Semaphore 、Event 、Condition 用来保证线程之间的同步,后者保证访问共享变量的互斥问题。

  • Lock & RLock:互斥锁,用来保证多线程访问共享变量的问题
  • Semaphore对象:Lock互斥锁的加强版,可以被多个线程同时拥有,而Lock只能被某一个线程同时拥有。
  • Event对象:它是线程间通信的方式,相当于信号,一个线程可以给另外一个线程发送信号后让其执行操作。
  • Condition对象:其可以在某些事件触发或者达到特定的条件后才处理数据

1、Lock(互斥锁)

请求锁定 — 进入锁定池等待 — — 获取锁 — 已锁定— — 释放锁

Lock(指令锁)是可用的最低级的同步指令。Lock处于锁定状态时,不被特定的线程拥有。Lock包含两种状态——锁定和非锁定,以及两个基本的方法。
可以认为Lock有一个锁定池,当线程请求锁定时,将线程至于池中,直到获得锁定后出池。池中的线程处于状态图中的同步阻塞状态。

构造方法:mylock = Threading.Lock( )

实例方法:

  • acquire([timeout]): 使线程进入同步阻塞状态,尝试获得锁定。
  • release(): 释放锁。使用前线程必须已获得锁定,否则将抛出异常。

实例一(未使用锁):

import threading
import time

num = 0

def show(arg):
    global num
    time.sleep(1)
    num +=1
    print('bb :{}'.format(num))

for i in range(5):
    t = threading.Thread(target=show, args=(i,))  # 注意传入参数后一定要有【,】逗号
    t.start()

print('main thread stop')

--------------------------------------------------------------------------
main thread stop
bb :1
bb :2
bb :3bb :4
bb :5

实例二(使用锁)

import threading
import time

num = 0

lock = threading.RLock()


# 调用acquire([timeout])时,线程将一直阻塞,
# 直到获得锁定或者直到timeout秒后(timeout参数可选)。
# 返回是否获得锁。
def Func():
    lock.acquire()
    global num
    num += 1
    time.sleep(1)
    print(num)
    lock.release()


for i in range(10):
    t = threading.Thread(target=Func)
    t.start()
------------------------------------------------------------------
1
2
3
4
5
6
7
8
9
10
#可以看出,全局变量在在每次被调用时都要获得锁,才能操作,因此保证了共享数据的安全性

对于Lock对象而言,如果一个线程连续两次release,使得线程死锁。所以Lock不常用,一般采用Rlock进行线程锁的设定。

import threading
import time

class MyThread(threading.Thread):
    def run(self):
        global num 
        time.sleep(1)

        if lock.acquire(1):  
            num = num+1
            msg = self.name+' set num to '+str(num)
            print(msg)
            lock.acquire()
            lock.release()
            lock.release()
num = 0
lock = threading.Lock()
def test():
    for i in range(5):
        t = MyThread()
        t.start()
if __name__ == '__main__':
    test()
------------------------------------------------------
Thread-12 set num to 1

2、RLock(可重入锁)

RLock(可重入锁)是一个可以被同一个线程请求多次的同步指令。RLock使用了“拥有的线程”和“递归等级”的概念,处于锁定状态时,RLock被某个线程拥有。拥有RLock的线程可以再次调用acquire(),释放锁时需要调用release()相同次数。可以认为RLock包含一个锁定池和一个初始值为0的计数器,每次成功调用 acquire()/release(),计数器将+1/-1,为0时锁处于未锁定状态。

  • 构造方法:mylock = Threading.RLock()

  • 实例方法:acquire([timeout])/release(): 跟Lock差不多。

实例解决死锁,调用相同次数的acquire和release,保证成对出现

import threading
rLock = threading.RLock()  #RLock对象
rLock.acquire()
rLock.acquire() #在同一线程内,程序不会堵塞。
rLock.release()
rLock.release()

print(rLock.acquire())

详细实例:

import threading
mylock = threading.RLock()
num = 0
class WorkThread(threading.Thread):
    def __init__(self, name):
        threading.Thread.__init__(self)
        self.t_name = name
    def run(self):
        global num
        while True:
            mylock.acquire()
            print('\n%s locked, number: %d' % (self.t_name, num))
            if num >= 2:
                mylock.release()
                print('\n%s released, number: %d' % (self.t_name, num))
                break
            num += 1
            print('\n%s released, number: %d' % (self.t_name, num))
            mylock.release()
def test(): #Python小白学习交流群:711312441
    thread1 = WorkThread('A-Worker')
    thread2 = WorkThread('B-Worker')
    thread1.start()
    thread2.start()
if __name__ == '__main__':
    test() 
--------------------------------------------------
A-Worker locked, number: 0

A-Worker released, number: 1

A-Worker locked, number: 1

A-Worker released, number: 2

A-Worker locked, number: 2

A-Worker released, number: 2

B-Worker locked, number: 2

B-Worker released, number: 2
相关文章
|
27天前
|
开发者 Python
如何在Python中管理模块和包的依赖关系?
在实际开发中,通常会结合多种方法来管理模块和包的依赖关系,以确保项目的顺利进行和可维护性。同时,要及时更新和解决依赖冲突等问题,以保证代码的稳定性和可靠性
44 4
|
7天前
|
Python
Python Internet 模块
Python Internet 模块。
102 74
|
25天前
|
算法 数据安全/隐私保护 开发者
马特赛特旋转算法:Python的随机模块背后的力量
马特赛特旋转算法是Python `random`模块的核心,由松本真和西村拓士于1997年提出。它基于线性反馈移位寄存器,具有超长周期和高维均匀性,适用于模拟、密码学等领域。Python中通过设置种子值初始化状态数组,经状态更新和输出提取生成随机数,代码简单高效。
104 63
|
26天前
|
测试技术 Python
手动解决Python模块和包依赖冲突的具体步骤是什么?
需要注意的是,手动解决依赖冲突可能需要一定的时间和经验,并且需要谨慎操作,避免引入新的问题。在实际操作中,还可以结合使用其他方法,如虚拟环境等,来更好地管理和解决依赖冲突😉。
|
26天前
|
持续交付 Python
如何在Python中自动解决模块和包的依赖冲突?
完全自动解决所有依赖冲突可能并不总是可行,特别是在复杂的项目中。有时候仍然需要人工干预和判断。自动解决的方法主要是提供辅助和便捷,但不能完全替代人工的分析和决策😉。
|
1月前
|
JSON Linux 数据格式
Python模块:从入门到精通,只需一篇文章!
Python中的模块是将相关代码组织在一起的单元,便于重用和维护。模块可以是Python文件或C/C++扩展,Python标准库中包含大量模块,如os、sys、time等,用于执行各种任务。定义模块只需创建.py文件并编写代码,导入模块使用import语句。此外,Python还支持自定义模块和包,以及虚拟环境来管理项目依赖。
Python模块:从入门到精通,只需一篇文章!
|
27天前
|
Python
Python的模块和包
总之,模块和包是 Python 编程中非常重要的概念,掌握它们可以帮助我们更好地组织和管理代码,提高开发效率和代码质量
38 5
|
26天前
|
数据可视化 Python
如何在Python中解决模块和包的依赖冲突?
解决模块和包的依赖冲突需要综合运用多种方法,并且需要团队成员的共同努力和协作。通过合理的管理和解决冲突,可以提高项目的稳定性和可扩展性
|
1月前
|
Python
在Python中,可以使用内置的`re`模块来处理正则表达式
在Python中,可以使用内置的`re`模块来处理正则表达式
46 5
|
1月前
|
Java 程序员 开发者
Python的gc模块
Python的gc模块