Python线程之同步机制实际应用场景举例说明
作者:雷学委 发布时间:2023-06-10 13:57:40
这次让我们来看看一个真实场景吧:银行转账
一、举例银行转账
假设现在有一个xuewei的账号里面有 100W。
然后有多个任务在转账,转入转出都是跟这个xuewei账号相关的。
而且这些任务发生是随机的。
我们先把上面的场景写成代码:
xuewei_account = 100
# amount为负数即是转出金额
def transfer(money):
global xuewei_account
xuewei_account += money
下面是多个线程,多线程模拟转账事件,我们假设有4个事件在同时发生。
import random
import threading
import datetime
import time
xuewei_account = 100
# amount为负数即是转出金额
def transfer(money):
global xuewei_account
xuewei_account += money
# 创建4个任务给学委账户转账
for i in range(10000):
threading.Thread(target=lambda: transfer(-1)).start()
threading.Thread(target=lambda: transfer(1)).start()
threading.Thread(target=lambda: transfer(-1)).start()
threading.Thread(target=lambda: transfer(1)).start()
# 等待活跃线程只剩下主线程MainThread
time.sleep(10)
print("-" * 16)
print("活跃线程数:", threading.active_count())
print("活跃线程:", threading.current_thread().name)
print("学委账户余额:", xuewei_account)
这里启动了4个线程循环了10000次,也就是4万个线程,分别于学委的账户进行转账。
下面是运行结果:
运行几次学委的账户还是正确的,余额还是100W。
上面的代码线程几万个,但每次运行的操作都很简单,完成一次加法。
线程一个接一个start,非常快速就切换下一个线程, 我们看到程序没有出现问题。
下面进行改造,这次不要就4万线程了,我们让转账这个任务耗时更多,每启动一个线程进行模拟10万次转账。
import random
import threading
import datetime
import time
xuewei_account = 100
# amount为负数即是转出金额
def transfer(money):
global xuewei_account
for x in range(100000):
xuewei_account += money
创建4个任务给重复学委账户转账:
for i in range(10):
threading.Thread(target=lambda: transfer(-1)).start()
threading.Thread(target=lambda: transfer(1)).start()
threading.Thread(target=lambda: transfer(-1)).start()
threading.Thread(target=lambda: transfer(1)).start()
time.sleep(10)
print("-" * 16)
print("活跃线程数:", threading.active_count())
print("活跃线程:", threading.current_thread().name)
print("学委账户余额:", xuewei_account)
这里运行的结果就比较出乎意料了:
多线程编程复杂的地方就在这里了, 有时候明明平平无奇的代码,改造成多线程,就很容易出bug!
当然上面的代码并不是平平无奇,相比第一段代码,上面的转账函数做的事件更多,更耗时。
二、问题解决
我们加上锁。
代码如下:
import random
import threading
import datetime
import time
xuewei_account = 100
lock = threading.Lock()
# amount为负数即是转出金额
def transfer(money):
lock.acquire()
global xuewei_account
for x in range(100000):
xuewei_account += money
lock.release()
# 创建4个任务给重复学委账户转账
for i in range(10):
threading.Thread(target=lambda: transfer(-1)).start()
threading.Thread(target=lambda: transfer(1)).start()
threading.Thread(target=lambda: transfer(-1)).start()
threading.Thread(target=lambda: transfer(1)).start()
time.sleep(10)
print("-" * 16)
print("活跃线程数:", threading.active_count())
print("活跃线程:", threading.current_thread().name)
print("学委账户余额:", xuewei_account)
运行结果如下:
上面的代码不管怎么运行,运行多少次最后学委的账户都是100.(PS:学委不会联系读者转账的,这个特别注意)。
不管多少个线程,每次转账函数内部转账的代码(从global到 += money这一段代码)只会被一个线程调用。
三、总结
展示了同步机制解决一些编程问题的思路。读者可以多多借鉴,思考锁的应用。
为什么在对amount重度操作(本文第二段代码)的时候,计算就出错了!
这里amount
相当于多线程都在操作的变量,也就是共享变量,多线程编程要特别注意这类变量,避免出现对共享变量的操作,有些程序在并发规模很小的时候一点问题也没有。
并发编程是高度利用CPU计算能力的编程方式,并发程序也就是在并行执行同类任务的程序。这个可以跟单线程应用比较。
来源:https://levin.blog.csdn.net/article/details/121943332
猜你喜欢
- 这里是一个使用日期函数的例子。下面的查询选择了所有记录,其date_col的值是在最后30天以内: mysql> SELECT som
- 一、变量和表达式>>> 1 + 1 &n
- 本文实例讲述了Python socket套接字实现C/S模式远程命令执行功能。分享给大家供大家参考,具体如下:一. 前言要求: 使用pyth
- 本人刚开始学习python,看了一段时间视频教程之后,决定做一个小游戏来巩固一下知识点,就做了一个文字版飞行棋,暂不具备图形界面。把代码贴出
- 前言本文的文字及图片来源于网络,仅供学习、交流使用,不具有任何商业用途,如有问题请及时联系我们以作处理。以下文章来源于Python进击者 ,
- 前言本文从单元测试实践角度出发,提升对代码质量的意识。本文内容主要包括:单元测试、Mock测试、基准测试。测试测试可以提高代码的质量、减少事
- 参考其他比较专业的博客系统,都在代码块上有一个复制代码的按钮。用来快速复制整个代码块的代码。于是我也想给我的博客增加一个这个功能。注:chr
- 最近在学习Python网络相关编程,这个代码实现了Telnet自动连接检测root用户密码,密码取自密码本,一个一个检测密码是否匹配,直到匹
- 一、怎么样取得最新版本的MySQL?要安装MySQL,首先要当然要取得它的最新版本,虽然大家都知道在FreeBSD的Packages中可以找
- 定义流的作用是使用统一的方式处理文件、网络和数据压缩等共用同一套函数和用法的操作。简单而言,流是具有流式行为的资源对象。因此,流可以线性读写
- 1、生成器函数包含yield from表达式。2、在yield from表达式处暂停委派生成器,调用方可直接将数据发送给子生成器。3、子生成
- 前言在前面的分享中,我们制作了一个天眼查 GUI 程序,今天我们在这个的基础上,继续开发新的功能,微博抓取工具,先来看下最终的效果整体的界面
- 前言众所周知Python不像JS或者PHP这种弱类型语言里在字符串连接时会自动转换类型,如果直接将字符串和数字拼接会直接报错。如以下的代码:
- 如果不用“with”,那么Python会在何时关闭文件呢?答案是:视情况而定。Python程序员最初学到的东西里有一点就是可以通过迭代法很容
- 1.增加维度下面给出两个样例样例1:[1, 2, 3] ==> [[1],[2],[3]]import tensorflow as t
- %r用rper()方法处理对象%s用str()方法处理对象相同结果有些情况下,两者处理的结果是一样的,比如说处理int型对象。例:print
- sysdate+(5/24/60/60) 在系统时间基础上延迟5秒 sysdate+5/24/60 在系统时间基础上延迟5分钟 sysdat
- 通过对Node的学习及应用,我们知道NodeJS其采用单线程、事件驱动、非阻塞I/O等架构设计,非常适用于高并发、I/O密集型应用。1. 什
- 本文实例讲述了Python计算已经过去多少个周末的方法。分享给大家供大家参考。具体如下:def weekends_between(d1,d2
- 在讲CSS优先级之前,我们得要了解什么是CSS,CSS是用来做什么的。首先,我们对CSS作一个简单的说明:CSS是层叠样式表(Cascadi