Python线程之如何解决共享变量问题

 更新时间:2022年02月24日 10:16:16   作者:雷学委  
这篇文章主要介绍了Python线程之如何解决共享变量问题,掐灭问我们学习了银行转账的这个场景,本文解决上次多个线程的操作都更改了amount变量导致运行结果不对的问题,需要的朋友可以参考一下

前面提到了银行转账这个场景,展示了一个比较耗时的转账操作。

这篇继续转帐,下面展示一段程序,多个线程的操作都更改了amount变量导致运行结果不对的问题。

前文说了转账问题

下面展示另一种转账的方式:

import random
import threading
import datetime
import time

xuewei = {'balance': 157}


# amount为负数即是转出金额
def transfer(money):
    name = threading.current_thread().getName()
    print("%s 给xuewei转账 %s " % (name, money))
    xuewei['balance'] += money
    print("xuewei账户余额:", xuewei['balance'])


lists = [-7, 20, -20, 7]  # 4次转账的数额,负数为学委的账户转出,正数为他人转入。
# 创建4个任务给学委转账上面lists的金额
threads = []
for i in range(4):
    amount = lists[i]
    name = "t-" + str(i)
    print("%s 计划转账 %s" % (name, amount))
    mythread = threading.Thread(name=name, target=lambda: transfer(amount))
    threads.append(mythread)

# 开始转账
for t in threads:
    t.start()

# 等待3秒让上面的转账任务都完成,我们在看看账户余额
time.sleep(3)
print("-" * 16)
print("学委账户余额:", xuewei['balance'])

这里启动了4个线程,每个线程内有个lambda表达式,分别于学委的账户进行转账,但是最后结果是185. 而不是157.

下面是运行结果:

PS: 这只是一种运行结果。多线程的运行结果不是永远一样的。

如何解决这个问题?

观测结果我们发先amount只保留了最后一个值。

好,下面改造一下:

import random
import threading
import datetime
import time

xuewei = {'balance': 157}

lists = [-7, 20, -20, 7]  # 4次转账的数额,负数为学委的账户转出,正数为他人转入。


def transfer(amount):
    name = threading.current_thread().getName()
    print("%s 给xuewei转账 %s " % (name,amount))
    xuewei['balance'] += amount
    print("xuewei账户余额:", xuewei['balance'])


# 创建4个任务给学委转账上面lists的金额
for i in range(4):
    amount = lists[i]
    name = str(i)
    # mythread = threading.Thread(name=name, target=lambda: transfer(amount))
    def event():
        print("%s 计划转账 %s" % (name, amount))
        transfer(amount)
    mythread = threading.Thread(name=name, target=event)
    mythread.start()


# 等待3秒让上面的转账任务都完成,我们在看看账户余额
time.sleep(3)
print("-" * 16)
print("学委账户余额:", xuewei['balance'])

学委这里加了一个event函数,把转账计划打印出来。

从下面的一次运行结果看,event函数的输出结果没错,所有”计划转账“金额都如预期[-7, 20, -20 7]。 问题是transfer函数再多线程执行的时候,我们发现amount被多线程竞争修改了:

用户0转账金额变成20
用户1转账金额变成-20
用户2转账金额变成7
用户3转账金额变成7

也就是说,amount被后面的线程修改了,但是前面线程还没有执行完。
用户0应该转账-7的,中间还没有执行完毕,结果被线程1修改了amount为20,用户0继续执行转账,余额变成177. 其他依次推理。

amount这个变量被多个线程竞争修改了,这个就是程序的共享变量。

到底如何解决?

方法非常简单:直接干掉共享变量。

下面就是消除共享变量的方法: 让共享变成每个线程访问独立运行空间

所以代码改动如下:

import random
import threading
import datetime
import time

xuewei = {'balance': 157}

lists = [-7, 20, -20, 7]  # 4次转账的数额,负数为学委的账户转出,正数为他人转入。
# 我们不要依赖amount变量了
def transfer():
    name = threading.current_thread().getName()
    xuewei['balance'] += lists[int(name)] #通过线程名字来获取对应金额
    print("xuewei账户余额:", xuewei['balance'])

# 创建4个任务给学委转账上面lists的金额
threads = []
for i in range(4):
    amount = lists[i]
    name = str(i)
    print("%s 计划转账 %s" % (name, amount))
    # mythread = threading.Thread(name=name, target=lambda: transfer())
    def event():
        transfer()
    mythread = threading.Thread(name=name, target=event)
    threads.append(mythread)

# 开始转账
for t in threads:
    t.start()

# 等待3秒让上面的转账任务都完成,我们在看看账户余额
time.sleep(3)
print("-" * 16)
print("学委账户余额:", xuewei['balance'])

运行结果如下:

上面的代码不管怎么运行,运行多少次最后学委的账户都是157.

这次展示的另一种方式来避开多线程出现bug的方法,使用一个list下标跟线程名字一一对应,这样只要是对应名字的线程拿到的数值不错错乱。

到此这篇关于Python线程之如何解决共享变量问题的文章就介绍到这了,更多相关Python线程解决共享变量问题内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Python实现定期检查源目录与备份目录的差异并进行备份功能示例

    Python实现定期检查源目录与备份目录的差异并进行备份功能示例

    这篇文章主要介绍了Python实现定期检查源目录与备份目录的差异并进行备份功能,涉及Python基于filecmp模块的文件比较及读写等相关操作技巧,需要的朋友可以参考下
    2019-02-02
  • 如何使用pycharm连接Databricks的步骤详解

    如何使用pycharm连接Databricks的步骤详解

    这篇文章主要介绍了如何使用pycharm连接Databricks,本文分步骤给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-09-09
  • Python简单I/O操作示例

    Python简单I/O操作示例

    这篇文章主要介绍了Python简单I/O操作,结合实例形式分析了Python针对文件的I/O读写及cPickle模块相关使用操作技巧,需要的朋友可以参考下
    2019-03-03
  • Python迭代和迭代器详解

    Python迭代和迭代器详解

    本篇文章主要介绍Python的迭代和迭代器,可迭代对象的相关概念,有需要的小伙伴可以参考下
    2016-11-11
  • pytorch动态神经网络(拟合)实现

    pytorch动态神经网络(拟合)实现

    这篇文章主要介绍了pytorch动态神经网络(拟合)实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-03-03
  • 攻击者是如何将PHP Phar包伪装成图像以绕过文件类型检测的(推荐)

    攻击者是如何将PHP Phar包伪装成图像以绕过文件类型检测的(推荐)

    这篇文章主要介绍了攻击者是如何将PHP Phar包伪装成图像以绕过文件类型检测的,需要的朋友可以参考下
    2018-10-10
  • 五种Python转义表示法

    五种Python转义表示法

    这篇文章主要介绍了五种Python转义表示法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-11-11
  • Python数据分析基础之异常值检测和处理方式

    Python数据分析基础之异常值检测和处理方式

    这篇文章主要介绍了Python数据分析基础之异常值检测和处理方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-07-07
  • pygame+opencv实现读取视频帧的方法示例

    pygame+opencv实现读取视频帧的方法示例

    由于pygame.movie.Movie.play()只支持MPEG格式的视频,所以决定使用与opencv读取视频帧的画面,本文就详细的介绍了pygame+opencv实现读取视频帧,感兴趣的可以了解一下
    2021-12-12
  • 如何使用Python 打印各种三角形

    如何使用Python 打印各种三角形

    这篇文章主要介绍了如何使用Python 打印各种三角形,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-06-06

最新评论