Python 线程同步锁, 信号量
同步锁
import time, threading
def addNum():
global num
num -= 1
num = 100
thread_list = []
for i in range(100):
t = threading.Thread(target=addNum)
t.start()
thread_list.append(t)
for t in thread_list:
t.join()
print('final num:', num)
运行结果:
final num: 0
import time, threading
def addNum():
global num
#num -= 1
tmp = num
time.sleep(0.00001)
num = tmp - 1
num = 100
thread_list = []
for i in range(100):
t = threading.Thread(target=addNum)
t.start()
thread_list.append(t)
for t in thread_list:
t.join()
print('final num:', num)
运行结果:
final num: 93
或
final num: 91
或
final num: 94
原因:
第一个程序中,num -= 1 这种写法,程序执行动作太快(完成这个动作在 cup 切换的时间内)
第二个程序中,把 num -= 1 , 加入了 sleep 时间,100个线程存在没有执行完就进行了切换,导致全局的 num 没有正常返回。引用下大神的图发现总结得非常好:

在上面的例子中 使用 join 方法会把整个线程停住,造成了串行,失去了多线程的意义,我们只需要在涉及到计算公共数据的时候串行执行即可。
使用同步锁处理计算公共的数据
import time, threading
def addNum():
global num
lock.acquire()
tmp = num
time.sleep(0.00001)
num = tmp - 1
lock.release()
num = 100
lock = threading.Lock()
thread_list = []
for i in range(100):
t = threading.Thread(target=addNum)
t.start()
thread_list.append(t)
for t in thread_list:
t.join()
print('final num:', num)
运算结果:
final num: 0
线程死锁和递归锁
import threading, time
class myThread(threading.Thread):
def doA(self):
lockA.acquire()
print(self.name, "gotlockA", time.ctime())
time.sleep(3)
lockB.acquire()
print(self.name, "gotlockB", time.ctime())
lockB.release()
lockA.release()
def doB(self):
lockB.acquire()
print(self.name, "gotlockB", time.ctime())
time.sleep(2)
lockA.acquire()
print(self.name, "gotlockA", time.ctime())
lockA.release()
lockB.release()
def run(self):
self.doA()
self.doB()
if __name__ == '__main__':
lockA = threading.Lock()
lockB = threading.Lock()
threads = []
for i in range(5):
threads.append(myThread())
for t in threads:
t.start()
for t in threads:
t.join()
#运行结果:
Thread-1 gotlockA Sat Jul 28 15:09:31 2018
Thread-1 gotlockB Sat Jul 28 15:09:34 2018
Thread-1 gotlockB Sat Jul 28 15:09:34 2018
Thread-2 gotlockA Sat Jul 28 15:09:34 2018
使用递归锁
import threading, time
class myThread(threading.Thread):
def doA(self):
lock.acquire()
print(self.name, "gotlockA", time.ctime())
time.sleep(3)
lock.acquire()
print(self.name, "gotlockB", time.ctime())
lock.release()
lock.release()
def doB(self):
lock.acquire()
print(self.name, "gotlockB", time.ctime())
time.sleep(2)
lock.acquire()
print(self.name, "gotlockA", time.ctime())
lock.release()
lock.release()
def run(self):
self.doA()
self.doB()
if __name__ == '__main__':
lock = threading.RLock()
threads = []
for i in range(5):
threads.append(myThread())
for t in threads:
t.start()
for t in threads:
t.join()
运行结果:
Thread-1 gotlockA Sat Jul 28 15:19:35 2018
Thread-1 gotlockB Sat Jul 28 15:19:38 2018
Thread-1 gotlockB Sat Jul 28 15:19:38 2018
Thread-1 gotlockA Sat Jul 28 15:19:40 2018
Thread-3 gotlockA Sat Jul 28 15:19:40 2018
Thread-3 gotlockB Sat Jul 28 15:19:43 2018
Thread-3 gotlockB Sat Jul 28 15:19:43 2018
Thread-3 gotlockA Sat Jul 28 15:19:45 2018
Thread-5 gotlockA Sat Jul 28 15:19:45 2018
Thread-5 gotlockB Sat Jul 28 15:19:48 2018
Thread-5 gotlockB Sat Jul 28 15:19:48 2018
Thread-5 gotlockA Sat Jul 28 15:19:50 2018
Thread-4 gotlockA Sat Jul 28 15:19:50 2018
Thread-4 gotlockB Sat Jul 28 15:19:53 2018
Thread-4 gotlockB Sat Jul 28 15:19:53 2018
Thread-4 gotlockA Sat Jul 28 15:19:55 2018
Thread-2 gotlockA Sat Jul 28 15:19:55 2018
Thread-2 gotlockB Sat Jul 28 15:19:58 2018
Thread-2 gotlockB Sat Jul 28 15:19:58 2018
Thread-2 gotlockA Sat Jul 28 15:20:00 2018
信号量
信号量用来控制线程并发数的,BoundedSemaphore或Semaphore管理一个内置的计数 器,每当调用acquire()时-1,调用release()时+1,计数器不能小于0,当计数器为 0时,acquire()将阻塞线程至同步锁定状态,直到其他线程调用release()。(类似于停车位的概念)。
BoundedSemaphore与Semaphore的唯一区别在于前者将在调用release()时检查计数 器的值是否超过了计数器的初始值,如果超过了将抛出一个异常。
import threading, time
class myThread(threading.Thread):
def run(self):
if semaphore.acquire():
print(self.name)
time.sleep(5)
semaphore.release()
if __name__ == "__main__":
semaphore = threading.Semaphore(5)
thrs = []
for i in range(20):
thrs.append(myThread())
for t in thrs:
t.start()
#运行结果:
Thread-1
Thread-2
Thread-3
Thread-4
Thread-5
Thread-6
Thread-7
Thread-9
Thread-10
Thread-8
Thread-11
Thread-13
Thread-14
Thread-12
Thread-15
Thread-18
Thread-16
Thread-17
Thread-19
Thread-20
import threading, time
class myThread(threading.Thread):
def run(self):
if semaphore.acquire():
print(self.name)
time.sleep(5)
semaphore.release()
if __name__ == "__main__":
semaphore = threading.BoundedSemaphore(5)
thrs = []
for i in range(20):
thrs.append(myThread())
for t in thrs:
t.start()
#运行结果:
Thread-1
Thread-2
Thread-3
Thread-4
Thread-5
Thread-6
Thread-8
Thread-10
Thread-9
Thread-7
Thread-12
Thread-14
Thread-15
Thread-13
Thread-11
Thread-16
Thread-17
Thread-20
Thread-19
Thread-18
Python 线程同步锁, 信号量的更多相关文章
- Python之路(第四十四篇)线程同步锁、死锁、递归锁、信号量
在使用多线程的应用下,如何保证线程安全,以及线程之间的同步,或者访问共享变量等问题是十分棘手的问题,也是使用多线程下面临的问题,如果处理不好,会带来较严重的后果,使用python多线程中提供Lock ...
- python线程同步原语--源码阅读
前面两篇文章,写了python线程同步原语的基本应用.下面这篇文章主要是通过阅读源码来了解这几个类的内部原理和是怎么协同一起工作来实现python多线程的. 相关文章链接:python同步原语--线程 ...
- python线程互斥锁Lock(29)
在前一篇文章 python线程创建和传参 中我们介绍了关于python线程的一些简单函数使用和线程的参数传递,使用多线程可以同时执行多个任务,提高开发效率,但是在实际开发中往往我们会碰到线程同步问题, ...
- 第十五章、Python多线程同步锁,死锁和递归锁
目录 第十五章.Python多线程同步锁,死锁和递归锁 1. 引子: 2.同步锁 3.死锁 引子: 4.递归锁RLock 原理: 不多说,放代码 总结: 5. 大总结 第十五章.Python多线程同步 ...
- Python并发编程-进程 线程 同步锁 线程死锁和递归锁
进程是最小的资源单位,线程是最小的执行单位 一.进程 进程:就是一个程序在一个数据集上的一次动态执行过程. 进程由三部分组成: 1.程序:我们编写的程序用来描述进程要完成哪些功能以及如何完成 2.数据 ...
- Python并行编程(五):线程同步之信号量
1.基本概念 信号量是由操作系统管理的一种抽象数据类型,用于在多线程中同步对共享资源的使用.本质上说,信号量是一个内部数据,用于标明当前的共享资源可以有多少并发读取. 同样在threading中,信号 ...
- Python线程同步
线程执行 join与setDaemon 子线程在主线程运行结束后,会继续执行完,如果给子线程设置为守护线程(setDaemon=True),主线程运行结束子线程即结束: 如果join()线程,那么主线 ...
- Python3 进程 线程 同步锁 线程死锁和递归锁
进程是最小的资源单位,线程是最小的执行单位 一.进程 进程:就是一个程序在一个数据集上的一次动态执行过程. 进程由三部分组成: 1.程序:我们编写的程序用来描述进程要完成哪些功能以及如何完成 2.数据 ...
- 线程同步、信号量、system v IPC
一.线程同步 条件变量 什么是条件变量? 线程A等待某个条件成立,条件成立,线程A才继续向下执行.线程B的执行使条件成立,条件成立以后唤醒线程A,以继续执行.这个条件就是条件变量. pthread_c ...
随机推荐
- 任务调度及远端管理(基于Quartz.net)
这篇文章我们来了解一些项目中的一个很重要的功能:任务调度 可能有些同学还不了解这个,其实简单点说任务调度与数据库中的Job是很相似的东西 只不过是运行的物理位置与管理方式有点不一样,从功能上来说我觉得 ...
- 使用tomcat插件运行java web项目
1 新建javaweb项目 使用骨架创建javaweb项目,具体步骤不熟悉的参见上一篇文章[idea集成maven]. 2 添加依赖 <dependency> <groupId> ...
- WebRTC 学习之 WebRTC 简介
本文使用的WebRTC相关API都是基于Intel® Collaboration Suite for WebRTC的. 相关文档链接:https://software.intel.com/sites/ ...
- JavaScript实现单张图片上传功能
前台jsp代码 <%@ page language="java" pageEncoding="UTF-8" contentType="text/ ...
- Shell-17--break-exit-continue-shift
echo -n 表示不换行 break 会退出当前循环 break 2 ,可以指定退出几层循环 continue 退出当次循环
- Telerik for AJAX RadGrid控件
作为一名.net小白,今天分享一下telerik知识的学习.熟悉ASP.NET Web Form的都知道Grid View或者是List View等表格控件,所以今天和大家分享一下telerik Ra ...
- 脚手架vue-cli系列四:vue-cli工程webpack的基本用法
webpack的打包依赖于它的一个重要配置文件webpack.config.js,在这个配置文件中就可以指定所有在源代码编译过程中的工作了,就一个配置就可以与冗长的Gruntfile或者Gulpfil ...
- linux中一些简便的命令之tr
tr是个简单字符处理命令,主要有以下几个用法: 1.替换字符: echo "hello,world" | tr 'a-z' 'A-Z' 执行结果:HELLO,WORLD 注释:这里 ...
- matlab中数组的拼接
matlab中,行拼接用逗号“:”,列拼接用分号“,”.示例如下: >> a=[1,2,3,4] 结果: a = 1 2 3 4 >> b=[1;2;3;4] 结果: b = ...
- Jwt Token 安全策略使用 ECDSA 椭圆曲线加密算法签名/验证
椭圆曲线密码学(Elliptic curve cryptography),简称 ECC,是一种建立公开密钥加密的算法,也就是非对称加密,ECDH 与 ECDSA 是基于 ECC 的算法.类似的还有 R ...