-
python3教程之PythonI/O进阶学习笔记_10.python的多线程(2)
本站最新发布 Python从入门到精通|Python基础教程
试听地址 https://www.xin3721.com/eschool/python.html
6 STORE_FAST 0 (a) 8 LOAD_CONST 0 (None) 10 RETURN_VALUE None 25 0 LOAD_FAST 0 (a) 2 LOAD_CONST 1 (1) 4 INPLACE_SUBTRACT 6 STORE_FAST 0 (a) 8 LOAD_CONST 0 (None) 10 RETURN_VALUE None
试听地址 https://www.xin3721.com/eschool/python.html
6 STORE_FAST 0 (a) 8 LOAD_CONST 0 (None) 10 RETURN_VALUE None 25 0 LOAD_FAST 0 (a) 2 LOAD_CONST 1 (1) 4 INPLACE_SUBTRACT 6 STORE_FAST 0 (a) 8 LOAD_CONST 0 (None) 10 RETURN_VALUE None
从字节码来看流程为:#1.load a #2.load 1 #3.add #4.赋值给a
任何一步字节码都是有可能被切换出去另外一个线程的字节码去操作a,可能在1线程运行到4字节码(a和1相加)的时候,开始运行2线程的6字节码(赋值给a)。
类似的有银行存取钱、商品库存等也会有这个问题。
2.2 线程如何同步?
用锁将这段代码段锁住,锁住时,不进行切换。直接运行完这段代码段。
a.Lock和Rlock
threading中有提供lock。
import threading from threading import Lock total=0 lock=Lock() def add(): global total global lock for i in range(1000000): lock.acquire() total += 1 lock.release() def desc(): global total global lock for i in range(1000000): lock.acquire() total -= 1 lock.release() if __name__=="__main__": add_total=threading.Thread(target=add) desc_total=threading.Thread(target=desc) add_total.start() desc_total.start() add_total.join() desc_total.join() print(total) pass
注意acquire和release成对存在。运行的时候会发现比不加锁的时候慢比较多。所以其实锁的问题也很明显:锁会影响性能,锁会引起死锁。死锁里有个非常常见的问题资源竞争是很容易发生的。
那能不能我锁里套着锁呢?Lock方法是不可以的,但是threading提供了Rlock可重入锁。
Rlock在同一个线程里面,可以连续调用多次acquire,但是注意acquire和release也一定是要成对存在的。
from threading import RLock total=0 lock=RLock() def add(): global total global lock for i in range(1000000): lock.acquire() lock.acquire() total += 1 lock.release() lock.release()
3.condition使用以及源码分析
condition是条件变量,用于复杂的线程间同步。
3.1 condition的使用
例子:现有一个需求,要求 天猫精灵和小爱一人一句进行对话。如果我们现用lock来实现是没办法做到这边说完一句,那边就说一句的。所以有了condition。
在这个例子中,需要用到condition的两个重要方法 notify()和wait()。notify()用于通知这边动作完成,wait()用于阻塞住等待消息。
#input import threading class XiaoAi(threading.Thread): def __init__(self,cond): self.cond=cond super().__init__(name="小爱") def run(self): with self.cond: print("小爱: 天猫在吗 我是小爱") self.cond.notify() #小爱print完了,信号发送 self.cond.wait() #小爱等待接受信号 print("小爱: 我们来背诗吧") self.cond.notify() class TianMao(threading.Thread): def __init__(self,cond): self.cond=cond super().__init__(name="天猫") def run(self): with self.cond: self.cond.wait() print("天猫: 在 我是天猫") self.cond.notify() self.cond.wait() print("天猫: 好啊") self.cond.notify() if __name__=="__main__": condition=threading.Condition() xiaoai=XiaoAi(condition) tianmao=TianMao(condition) tianmao.start() xiaoai.start() #output: 小爱: 天猫在吗 我是小爱 天猫: 在 我是天猫 小爱: 我们来背诗吧 天猫: 好啊
ps:需要注意的是
- condition必须先with 再调用 notify和wait方法
- 这么写的时候,线程的start()顺序很重要
3.2 Condition源码分析
condition其实是有两层锁的。一把底层锁,会在线程调用了wait()的时候释放。
上层锁会在wait()的时候放入双端队列中,在调用notify()的时候被唤醒。
a.condition=threading.Condition()
condition初始化的时候申请了一把锁
.png)
b.self.cond.wait()
先释放了condition初始化的时候申请的底层锁,然后又申请了锁放入双端队列。
栏目列表
最新更新
python数据库连接池技术总结
python数据库连接池技术总结
成人网站性能提升 20 倍之经验谈 [Python
python动态捕获异常
python 探测网站目录的GUI程序
python实现中文字符繁体和简体中文转换
Python服务器开发 -- 网络基础
python高性能编程方法一
使用python管理Cisco设备
python抓取google搜索结果
基于UDP的服务器端和客户端
再谈UDP和TCP
在socket编程中使用域名
网络数据传输时的大小端问题
socket编程实现文件传输功能
如何优雅地断开TCP连接?
图解TCP四次握手断开连接
详细分析TCP数据的传输过程
图解TCP数据报结构以及三次握手(非常详
TCP协议的粘包问题(数据的无边界性)
Excel数据导入到Sql server
SQL Server like 字段
SQL Server中的LEFT、RIGHT函数
sql server 安装出现需要sqlncli.msi文件,错误
SQL Server学习内容(一)
SQLServer执行大脚本文件时,提示“无法执
数据库敏捷版本控制之3个数据库策略
将select 转为json
SQL Server 创建索引(index)
GROUP BY中的WITH CUBE、WITH ROLLUP原理测试及