Python并发——线程安全与Lock解决方案

本篇文章为本人学习python并发编程的过程记录,欢迎感兴趣的同学们交流讨论!

1. 什么是线程安全?

  • 线程安全指的是某个函数或某个函数库在多线程的运行环境下,能够正确处理各个线程之间的共享变量,保证程序运行的安全性。
  • 线程不安全则是受到多线程程序运行的特性影响,造成相应的程序的逻辑性错误,从而产生严重的安全隐患。

2. 使用Lock解决线程的安全问题

  • Lock可以在“关键的位置”提供串行特性,保证数据安全与独立
  • 形象理解:我们可以将关键的方法或变量理解为一个隧道,而Lock则是在隧道门口添加的一位 “守门员” ,每一个从这里经过的线程都需要跟这位守门员打声招呼,而守门员的责任则是:当隧道中有人时让后面的人等待,当隧道中没有人时放行。

3. Lock的两种使用方法

  • 定义锁
import threading
lock = threading.Lock()
  • try-finally模式
lock.acquire() # 获取锁
try:
	...
finally:
	lock.release() # 释放锁
  • with 模式
with lock:
	...

更常使用的是with模式

4. 银行取钱示例

import threading
import time

# 创建一个Lock
lock = threading.Lock() 

class Account: # 定义Account类
	def __init__(self, balance):
		self.balance = balance
	
def draw_0(account, money):  # 不启用Lock
		if account.balance > money:
			time.sleep(0.1)  # 通过sleep造成线程阻塞
			account.balance -= money
			print('取钱成功!')
		else:
			print('取钱失败!')

def draw_1(account, money):
		with lock:  # 启用Lock
			if account.balance > money:
				time.sleep(0.1) # 即使有sleep仍然线程安全
				account.balance -= money
				print('取钱成功!')
			else:
				print('取钱失败!')

if __name__ == '__main__':
	account = Account(1000) # 开设一个账户
	# 未启用线程安全的版本,由于有sleep的存在,必定造成不安全现象
	# thread_0 = threading(name='thread_0', target=draw_0, args=(800,))
	# thread_1 = threading(name='thread_1', target=draw_0, args=(800,))
	# 线程安全版本,启用Lock
	thread_0 = threading(name='thread_0', target=draw_1, args=(800,))
	thread_1 = threading(name='thread_1', target=draw_1, args=(800,))

这里有一个小问题需要进行一下说明,有的同学在看了上面的例子或者没有好好理解的情况下,会认为使用Lock会将多线程打回原形,重新变为串行。需要注意的是,在上面的例子中,由于案例十分简单,实际上也确实回到了串行操作,但是我们需要知道的是,在实际的业务中,可能存在非常多不同的线程,各个线程执行这不同的工作,如网络信息传输加载等等;在这种情况下,线程安全才表现出它的重要行,可以想见,当因为Lock出现阻塞时(Lock只能够阻塞起负责的部分),并非变为了完全串行,仍然有其他的线程可以使用CPU。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值