python并发编程笔记4
是根据蚂蚁学Python的视频做的笔记,方便自己后续回顾
视频链接:BV1bK411A7tV
老师的源码
这一份笔记对应的是视频的P6
文章目录
P6-Python线程安全问题以及解决方案
1、线程安全概念介绍
线程安全:指某个函数、函数库在多线程环境中被调用时,能够正确地处理多个线程之间的共享变量,使程序功能正确完成。
线程不安全:由于线程的执行随时会发生切换,就造成了不可预料的结果,出现线程不安全
如下图:i代码是没有问题的,但如果if语句判断完,发生线程切换,就会造成错误
2、Lock用于解决线程安全问题
2.1、try-finally模式
import threading
# 获取lock对象
lock = threading.Lock()
# 获取这个锁
lock.acquire()
try:
# do something
finally:
# 释放锁
lock.release()
2.2、with模式
import threading
lock = threading.Lock()
with:
# do something
把代码放到lock里面,就不会出现上述提到的取钱扣多钱的问题
3、实例代码演示问题以及解决方案
3.1、随机可能出错版本:
# 03lock_concurrent.py
import threading
# 创建一个账号类
class Account:
def __init__(self, balance):
self.balance = balance
# 取钱函数
def draw(account, amount):
if account.balance >= amount:
print(threading.current_thread().name,
"取钱成功")
account.balance -= amount
print(threading.current_thread().name,
"余额", account.balance)
else:
print(threading.current_thread().name,
"取钱失败,余额不足")
if __name__ == '__main__':
# 实例账号对象,1000元进账户
account = Account(1000)
# 实例俩个线程对象
ta = threading.Thread(name="ta", target=draw, args=(account, 800))
tb = threading.Thread(name="tb", target=draw, args=(account, 800))
# 启动两个线程对象
ta.start()
tb.start()
3.2、一定出问题(添加sleep语句):
sleep语句一定会导致当前线程阻塞,阻塞就会切换线程
# 03lock_concurrent.py
import threading
import time
# 创建一个账号类
class Account:
def __init__(self, balance):
self.balance = balance
# 取钱函数
def draw(account, amount):
if account.balance >= amount:
# sleep语句一定会导致当前线程阻塞,阻塞就会切换线程
time.sleep(0.1)
print(threading.current_thread().name,
"取钱成功")
account.balance -= amount
print(threading.current_thread().name,
"余额", account.balance)
else:
print(threading.current_thread().name,
"取钱失败,余额不足")
if __name__ == '__main__':
# 实例账号对象,1000元进账户
account = Account(1000)
# 实例俩个线程对象
ta = threading.Thread(name="ta", target=draw, args=(account, 800))
tb = threading.Thread(name="tb", target=draw, args=(account, 800))
# 启动两个线程对象
ta.start()
tb.start()
3.3、解决方案:with模式
在类上添加lock = threading.Lock(),并将draw函数嵌入with中
# 03lock_concurrent.py
import threading
import time
lock = threading.Lock()
# 创建一个账号类
class Account:
def __init__(self, balance):
self.balance = balance
# 取钱函数
def draw(account, amount):
with lock:
if account.balance >= amount:
# sleep语句一定会导致当前线程阻塞,阻塞就会切换线程
time.sleep(0.1)
print(threading.current_thread().name,
"取钱成功")
account.balance -= amount
print(threading.current_thread().name,
"余额", account.balance)
else:
print(threading.current_thread().name,
"取钱失败,余额不足")
if __name__ == '__main__':
# 实例账号对象,1000元进账户
account = Account(1000)
# 实例俩个线程对象
ta = threading.Thread(name="ta", target=draw, args=(account, 800))
tb = threading.Thread(name="tb", target=draw, args=(account, 800))
# 启动两个线程对象
ta.start()
tb.start()