ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

python-不安全的并发(同步锁)

2022-05-12 10:02:16  阅读:217  来源: 互联网

标签:account 同步 python global t2 t1 并发 线程 balance


一、为什么不安全

【1】假设a的银行账户有balance=500,此时公司像银行账户转入工资1000元,a此时又在淘宝上购买200元的商品。因为并发,如果此时银行获取balance=500,在银行系统内a的账户内就有1500元,此时该结果还没返回到a账户,这个时候淘宝也拿到了balance=500,并且减-200=300,返回到a账户内,此时balance=300;淘宝结算结束后,银行系统内的结果才返回到a账户,这个时候a账户内balance=1500

【2】不进行锁 ,则以下代码会造成输出的时候,有时候是200,有时候是1500

# -*- coding:utf-8 -*-
# __author__:pansy
# 2022/5/11

# 账户余额
import time,threading

account_balance = 500
def foo(num):
    # 需要返回最终的account_balance,因为该变量是全局变量,在局部作用域内只能声明,不能修改;如果要修改必须声明为global
    global account_balance
    # 引用账户余额,赋值给balance(引用的时候不需要将account_balance声明为global)
    balance = account_balance
    time.sleep(1)
    # balance变量要加上函数传进来的入参
    balance = balance + num
    # 返回最终的结果,此时修改了account_balance,所以要 global account_balance
    account_balance = balance

# 创建线程
t1 = threading.Thread(target=foo,args=(1000,)) # 银行打钱进来
t2 = threading.Thread(target=foo,args=(-300,)) # 淘宝消费

# 启动线程
t1.start()
t2.start()

# 需要阻塞主线程,当t1和t2线程结束后,主线程再执行打印,然后再结束主线程
t1.join()
t2.join()

# 最终余额打印
print('最终余额为:%.2f' % account_balance) # 输出可能是200.00,可能是1500.00

二、同步锁

【1】既然不安全,那只需要把重要数据balance锁住,当线程1在使用balance的时候,把balance锁定只能给该线程用;线程2被挡住无法使用balance;当线程1使用完balance后,再放开balance,线程2调用balance同时再次将balance锁住

【2】创建对象threading.Lock()

# -*- coding:utf-8 -*-
# __author__:pansy
# 2022/5/11

# 账户余额
import time,threading
# 创建锁
r = threading.Lock() # 同步锁

account_balance = 500
def foo(num):
    # 在操作重要数据前,先锁定
    r.acquire()

    # 需要返回最终的account_balance,因为该变量是全局变量,在局部作用域内只能声明,不能修改;如果要修改必须声明为global
    global account_balance
    # 引用账户余额,赋值给balance(引用的时候不需要将account_balance声明为global)
    balance = account_balance
    time.sleep(1)
    # balance变量要加上函数传进来的入参
    balance = balance + num
    # 返回最终的结果,此时修改了account_balance,所以要 global account_balance
    account_balance = balance

    # 操作完重要数据后,解锁
    r.release()

# 创建线程
t1 = threading.Thread(target=foo,args=(1000,)) # 银行打钱进来
t2 = threading.Thread(target=foo,args=(-300,)) # 淘宝消费

# 启动线程
t1.start()
t2.start()

# 需要阻塞主线程,当t1和t2线程结束后,主线程再执行打印,然后再结束主线程
t1.join()
t2.join()

# 最终余额打印
print('最终余额为:%.2f' % account_balance) # 最终输出始终为1200.00

 

标签:account,同步,python,global,t2,t1,并发,线程,balance
来源: https://www.cnblogs.com/flowers-pansy/p/16257471.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有