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

> 作者/来源: UCloud 运营管理员
> 发布时间: 2022-12-15T06:59:00.000Z
> 分类: 其他
> 标签: Python
> 原文链接: http://117.50.162.249:3000/yun/articles/2063

---

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

> 来源: https://www.ucloud.cn/yun/128429.html
> 作者: 89542767
> 发布日期: 发布于2022-12-15 14:59

Python作为一门比较常见的编程语言，可以对其进行多线程的编程，包括利用Lock与RLock，实现多线程之间的相互同步，那么，实现这种原理的机制到底是什么样子的呢？下面就给大家详细解答下。

**什么是锁机制？**

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

**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)
```

　　运行截图如下：

![01.png](https://ucloud-blog.cn-bj.ufileos.com/articles/128429/images/128429_000.png)

　　运行结果

　　当我们多次运行时，可以看到最终的结果都几乎不等于我们期待的值即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)
```

　　运行截图如下：

![02.png](https://ucloud-blog.cn-bj.ufileos.com/articles/128429/images/128429_001.png)

　　运行结果

　　从运行结果可以看到，不论我们运行多少次改代码，其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.RLock，RLock内部维护着一个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()
```

　　综上所述，这篇文章就给大家介绍到这里了，希望可以给大家带来帮助。