Python并行编程多线程锁机制Lock与RLock实现线程同步

目录

什么是锁机制?

Lock() 管理线程

RLock() 与Lock()的区别

什么是锁机制?

要回答这个问题,我们需要知道为什么需要使用锁机制。前面我们谈到一个进程内的多个线程的某些资源是共享的,这也是线程的一大优势,但是也随之带来一个问题,即当两个及两个以上的线程同时访问共享资源时,如果此时没有预设对应的同步机制,就可能带来同一时刻多个线程同时访问同一个共享资源,即出现竞态,多数情况下我们是不希望出现这样的情况的,那么怎么避免呢?

Lock() 管理线程

先看一段代码:

import threading import time resource = 0 count = 1000000 resource_lock = threading.Lock() def increment(): global resource for i in range(count): resource += 1 def decerment(): global resource for i in range(count): resource -= 1 increment_thread = threading.Thread(target=increment) decerment_thread = threading.Thread(target=decerment) increment_thread.start() decerment_thread.start() increment_thread.join() decerment_thread.join() print(resource)

运行截图如下:

运行结果

当我们多次运行时,可以看到最终的结果都几乎不等于我们期待的值即resource初始值0

为什么呢? 原因就是因为 += 和 -=并不是原子操作。

可以使用dis模块查看字节码:

import dis def add(total): total += 1 def desc(total): total -= 1 total = 0 print(dis.dis(add)) print(dis.dis(desc)) # 运行结果: # 3 0 LOAD_FAST 0 (total) # 3 LOAD_CONST 1 (1) # 6 INPLACE_ADD # 7 STORE_FAST 0 (total) # 10 LOAD_CONST 0 (None) # 13 RETURN_VALUE # None # 5 0 LOAD_FAST 0 (total) # 3 LOAD_CONST 1 (1) # 6 INPLACE_SUBTRACT # 7 STORE_FAST 0 (total) # 10 LOAD_CONST 0 (None) # 13 RETURN_VALUE # None

那么如何保证初始值为0呢? 我们可以利用Lock(),代码如下:

import threading import time resource = 0 count = 1000000 resource_lock = threading.Lock() def increment(): global resource for i in range(count): resource_lock.acquire() resource += 1 resource_lock.release() def decerment(): global resource for i in range(count): resource_lock.acquire() resource -= 1 resource_lock.release() increment_thread = threading.Thread(target=increment) decerment_thread = threading.Thread(target=decerment) increment_thread.start() decerment_thread.start() increment_thread.join() decerment_thread.join() print(resource)

运行截图如下:

运行结果

从运行结果可以看到,不论我们运行多少次改代码,其resource的值都为初始值0, 这就是Lock()的功劳,即它可以将某一时刻的访问限定在单个线程或者单个类型的线程上,在访问锁定的共享资源时,必须要现获取对应的锁才能访问,即要等待其他线程释放资源,即resource_lock.release()当然为了防止我们对某个资源锁定后,忘记释放锁,导致死锁,我们可以利用上下文管理器管理锁实现同样的效果:

import threading import time resource = 0 count = 1000000 resource_lock = threading.Lock() def increment(): global resource for i in range(count): with resource_lock: resource += 1 def decerment(): global resource for i in range(count): with resource_lock: resource -= 1 increment_thread = threading.Thread(target=increment) decerment_thread = threading.Thread(target=decerment) increment_thread.start() decerment_thread.start() RLock() 与Lock()的区别

我们需要知道Lock()作为一个基本的锁对象,一次只能一个锁定,其余锁请求,需等待锁释放后才能获取,否则会发生死锁:

import threading resource.lock = threading.lock() resource = 0 resource.lock.acquire() resource.lock.acquire() resource += 1 resource.lock.release() resource.lock.release()

为解决同一线程中不能多次请求同一资源的问题,python提供了“可重入锁”:threading.RLockRLock内部维护着一个Lock和一个counter变量,counter记录了acquire的次数,从而使得资源可以被多次acquire

直到一个线程所有的acquire都被release,其他的线程才能获得资源 。用法和threading.Lock类相同,即比如递归锁的使用:

import threading lock = threading.RLock() def dosomething(lock): lock.acquire() # do something lock.release() lock.acquire() dosomething(lock) lock.release()

以上就是Python并行编程多线程锁机制Lock与RLock实现线程同步的详细内容,更多关于Python锁Lock RLock线程同步的资料请关注易知道(ezd.cc)其它相关文章!

推荐阅读

    设置线程名称|tomcat线程名称设置

    设置线程名称|tomcat线程名称设置,,1. tomcat线程名称设置一.tomcat的优化1.tomcat的自身调优采用动静分离调优Tomcat线程池调优Tomcat的

    多线程cpu电脑|多线程的CPU

    多线程cpu电脑|多线程的CPU,,1. 多线程的CPU四核心四线程,表示这个电脑的CPU核心是4个核心、4个线程的。电脑CPU的核心数量和线程数量越多,

    简单的线程池(三)

    简单的线程池(三),吞吐量,线程,◆ 概要本文中,作者针对 《简单的线程池(一)》 和 《简单的线程池(二)》 介绍的两个线程池分别进行了并发测试。基

    Common Lisp支持多线程吗

    Common Lisp支持多线程吗,语言,都是,本文目录Common Lisp支持多线程吗能推荐下比较经典的common lisp 代码么相比Scheme 与 Common Lisp,Cl

    超线程技术是什么

    超线程技术是什么,超线程技术,性能,超线程,提升,执行,线程,超线程技术是什么超线程技术是在一颗CPU同时执行多个程序而共同分享一颗CPU内的资源

    英特尔超线程技术是什么

    英特尔超线程技术是什么,英特尔,超线程技术,处理器,性能,运算,酷睿,  当今英特尔超线程技术(英特尔 HT 技术)在每个处理器上提供线程层并行,从