Python的线程06 认识线程安全 【文末送书】

编程入门 行业动态 更新时间:2024-10-23 22:21:52

Python的<a href=https://www.elefans.com/category/jswz/34/1771240.html style=线程06 认识线程安全 【文末送书】"/>

Python的线程06 认识线程安全 【文末送书】

正式的Python专栏第44篇,同学站住,别错过这个从0开始的文章!

前面学委分享了5篇多线程的文章了,一开始写多线程程序好像非常简单。可是实际应用跟第4篇,第5篇的场景比较像,而且还更复杂。

有没有安全方法进行多线程编程? 我们先学习一下‘线程安全’了。

分享之前,学委把上次送书的视频公开发布到B站:

不定期抽奖第二期 - 定时抽奖实测

什么是线程安全?

线程安全,名字就非常直接,在多线程情况下是安全的,多线程操作上的安全。

比如一个计算加法的函数,不管是一千个还是一万个线程,我们希望它执行的结果总是正确的,1+1 必须永远等于2, 而不是线程少的时候1+1 变成3或者4了。

通常我们都用线程安全来修饰一个类,修饰一个函数。

我们会说我设计的这个类是线程安全的
这意味着,在多线程环境下,同时调用这个类的函数不会出现函数设置预期之外的异常(上述的1+1=3的情况)

在Python中有哪些类是线程安全的?

dict 和 list,tuple这些都是线程安全。

它们是被全局解释器保障了,这个锁:GIL(全局解释器锁)确保了任何时候只能有一个线程执行相应操作的字节码

.html#term-global-interpreter-lock

但是这番话也是说的不清不楚的。

现在我们拿转账来解析吧:


xuewei_account = dict()
xuewei_account['amount'] = 100# amount为负数即是转出金额
def transfer(money):xuewei_account['amount'] +=  money

如上,代码为一个函数对xuewei_account(账户)进行转入金额操作。

这里用了dict类型,GIL会保证只有一个线程操作账户。

下面是多个线程进行操作的代码:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2021/11/24 12:02 上午
# @Author : LeiXueWei
# @CSDN/Juejin/Wechat: 雷学委
# @XueWeiTag: CodingDemo
# @File : testthread_safe.py
# @Project : hello
import random
import threading
import datetime
import timexuewei_account = dict()
xuewei_account['amount'] = 100# amount为负数即是转出金额
def transfer(money):xuewei_account['amount'] +=  money# 创建4个任务给重复学委账户转账
threads = []
for i in range(200):t1 = threading.Thread(target=lambda: transfer(-1))threads.append(t1)t2 = threading.Thread(target=lambda: transfer(1))threads.append(t2)for t in threads:t.start()# 这次不用sleep了,用join来等待所有线程执行完毕
# join函数必须线程start后才能调用,否则出错。
for t in threads:t.join()print("-" * 16)
print("活跃线程数:", threading.active_count())
print("活跃线程:", threading.current_thread().name)
print("学委账户余额:", xuewei_account)

这段代码运行的输出结果正常,因为是反复+1/-1,最后肯定是恢复原账户余额。

虽然多个线程,但是每个线程只对xuewei_account进行一次读写,这时候dict是安全的。

但是我们把赋值修改dict的操作变多之后(特别是一个线程内反复多次获取值然后修改),像下面的代码:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2021/11/24 12:02 上午
# @Author : LeiXueWei
# @CSDN/Juejin/Wechat: 雷学委
# @XueWeiTag: CodingDemo
# @File : testthread_safe.py
# @Project : hello
import random
import threading
import datetime
import timexuewei_account = dict()
xuewei_account['amount'] = 100# amount为负数即是转出金额
def transfer(money):for i in range(100000):xuewei_account['amount'] = xuewei_account['amount'] + money# 创建400个任务重复给学委账户转账
threads = []
for i in range(200):t1 = threading.Thread(target=lambda: transfer(-1))threads.append(t1)t2 = threading.Thread(target=lambda: transfer(1))threads.append(t2)for t in threads:t.start()
for t in threads:t.join()print("-" * 16)
print("活跃线程数:", threading.active_count())
print("活跃线程:", threading.current_thread().name)
print("学委账户余额:", xuewei_account)

这是某一次运行结果(不保证每次acount的数值一样):

我们看到dict还是扛不住多个线程反复的写操作。

这里区别是:每个线程只对xuewei_account进行大量读写,虽然dict是安全的,但是多个线程中间穿插修改了account,程序方法栈出现操作到旧值(看下面的图)。

主要是下面这段代码:

xuewei_account[‘amount’] += money # 即是 xuewei_account[‘amount’] = xuewei_account[‘amount’]+ money

再一步抽象简化可以写成:

a = a + b

每个线程都执行 +b 操作,最后a的值应该是a+2b。

上面的操作意味这下面的情况发生了:

在某个线程中可能出现某一个线程T1获取了a值 ,准备加上b。

另外一个线程T2已经完成了a+b操作,把a的值变成了a+b了。

但是接下来T1 拿了a的值再执行a+b操作,把a的值变成a+b。

这样就少加了一个b,本来最后结果是a+2b 的变成了 a+b(因为T1拿了a的旧值,中间T2执行完,T1才继续执行)

当然实际多线程之间交互比上图还要随机。

如何做到真正线程安全?

dict读取数据是线程安全,但是被反复读写就容易出现数据混乱。

如果我们要设计一个线程安全的函数,那么它必须不涉及任何共享变量或者是完全没有状态依赖的函数

def thread_safe_method():pass

无状态函数

比如下面的加法函数,不管多少个线程调用,返回值永远是预期的a+b。

def add(a, b):return a + b

另一种 化繁为简

或许我们可以把多线程转换为单线程,这个需要一个线程安全的媒介

也就是下一篇讲到的:线程安全队列。

书籍赠送 :《Axure RP 原型设计实践(Web+APP)》

简介

《Axure RP 原型设计实践(Web+APP)》是一本通过大量案例介绍Axure RP原型设计的教程。
全书分为三篇,分别为Axure RP基础、Axure RP高级功能和Axure RP原型设计实践。包括产品原型设计、Axure RP概述、基础元件、高级元件、元件交互、母版、Axure Share共享原型、团队项目、输出文档、Web原型设计实践、App原型设计实践、菜单原型设计实践、整站原型设计——温馨小居共13章内容,附录部分对原型设计中的众多常见问题专门进行了解答。
《Axure RP 原型设计实践(Web+APP)》主要面向产品经理、需求分析师、架构师、用户体验设计师、网站策划师、交互设计师、产品助理等,以及高校计算机及相关专业师生。

目录和更多书籍信息

.html
.html

好用的原型设计工具可以快速的制作产品(MVP),不限于网站/App,Axure RP 这个工具还是应用非常广泛的。

各位开发读者们想要把应用做的更加专业,有条理,可以多看看这类资料。了解产品设计,可以程序更加产品化,专业化,更好交互,而不是天马行空堆一个四不像。

学委这里想分享的是,有些业务可以开发为N个接口协作,配套界面N个操作做完,但是通过高效产品设计,可以把这个交互过程做的很人性化,很友好,就像一切刚出苹果手机一样,简洁又傻瓜式的操作。

特别是有些独立开发者,一条龙全包了项目,包括产品设计,开发编码发布等,值得入手。

对了,喜欢Python的朋友,请关注学委的 Python基础专栏 or Python入门到精通大专栏

持续学习持续开发,我是雷学委!
编程很有趣,关键是把技术搞透彻讲明白。
欢迎关注微信,点赞支持收藏!

更多推荐

Python的线程06 认识线程安全 【文末送书】

本文发布于:2024-03-09 04:33:18,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1723819.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:线程   Python   文末送书

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!