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

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

这篇继续转帐,下面展示一段程序,多个线程的操作都更改了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线程解决共享变量问题内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • python 多线程共享全局变量的优劣

    一.多线程共享全局变量 首先我们来回忆下在函数中修改全局变量的情况. 在一个函数中,对全局变量进行修改的时候,到底是否需要使用 global 进行说明,要看是否对全局变量的执行指向进行了修改. 如果修改了执行指向,即让全局变量指向了一个新的地方,那么必须使用 global. 如果仅仅是修改了指向的空间中的数据,此时不是必须要使用 global. 我们来看一个例子,在这个例子中,让一个子线程对全局变量 +1 操作,另一个子线程只打印全局变量,看看数据是否共享. from threading imp

  • 探究Python多进程编程下线程之间变量的共享问题

     1.问题: 群中有同学贴了如下一段代码,问为何 list 最后打印的是空值? from multiprocessing import Process, Manager import os manager = Manager() vip_list = [] #vip_list = manager.list() def testFunc(cc): vip_list.append(cc) print 'process id:', os.getpid() if __name__ == '__main_

  • 互斥锁解决 Python 中多线程共享全局变量的问题(推荐)

    一.同步概念 同步就是协同步调,按预定的先后次序进行运行.如:你说完,我再说. "同"字从字面上容易理解为一起动作. 其实不是,在这里,"同"字应是指协同.协助.互相配合. 线程同步,可理解为线程A和B一块配合,A执行到一定程度时要依靠B的某个结果,于是停下来,示意B运行:B执行,再将结果给A:A再继续操作. 之前我们遇到过,如果多个线程共同对某个数据修改,则可能出现不可预料的结果,为了保证数据的正确性,需要对多个线程进行同步. 解决线程同时修改全局变量的方式 我们

  • python多线程共享变量的使用和效率方法

    python多线程可以使任务得到并发执行,但是有时候在执行多次任务的时候,变量出现"意外". import threading,time n=0 start=time.time() def b1(num): global n n=n+num n=n-num def b2(num): for i in range(1000000): b1(num) t1=threading.Thread(target=b2,args=(5,)) t2=threading.Thread(target=b2

  • Python 多线程共享变量的实现示例

    多线程-共享全局变量 #coding=utf-8 from threading import Thread import time g_num = 100 def work1(): global g_num for i in range(3): g_num += 1 print("----in work1, g_num is %d---"%g_num) def work2(): global g_num print("----in work2, g_num is %d---&

  • 浅谈python多线程和多线程变量共享问题介绍

    1.demo 第一个代码是多线程的简单使用,编写了线程如何执行函数和类. import threading import time class ClassName(threading.Thread): """创建类,通过多线程执行""" def run(self): for i in range(5): print(i) time.sleep(1) def sing(): for i in range(1,11): print("唱歌第

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

    前面提到了银行转账这个场景,展示了一个比较耗时的转账操作. 这篇继续转帐,下面展示一段程序,多个线程的操作都更改了amount变量导致运行结果不对的问题. 前文说了转账问题 下面展示另一种转账的方式: import random import threading import datetime import time xuewei = {'balance': 157} # amount为负数即是转出金额 def transfer(money):     name = threading.curr

  • Python提示[Errno 32]Broken pipe导致线程crash错误解决方法

    本文实例讲述了Python提示[Errno 32]Broken pipe导致线程crash错误解决方法.分享给大家供大家参考.具体方法如下: 1. 错误现象 ThreadingHTTPServer 实现的 http 服务,如果客户端在服务器返回前,主动断开连接,则服务器端会报 [Errno 32] Broken pipe 错,并导致处理线程 crash. 下面先看个例子,python 版本: 2.7 示例代码 复制代码 代码如下: #!/usr/bin/env python #!coding=u

  • 解决python线程卡死的问题

    1. top命令和日志方式判定卡死的位置 python代码忽然卡死,日志不输出,通过如下方式可以确定线程确实已经死掉了: # top 命令 top命令可以看到机器上所有线程的执行情况,%CPU和%MEM可以看出线程消耗的资源情况 由于机器上线程数量太多,可能要查看的线程的信息在top命令当前屏幕上显示不出来可以通过如下方式查看 在top命令下输入:u 接下来会提示输入用户名,就可以查看该用户所执行的所有线程 Which user (blank for all): denglinjie 这样就可以

  • Python线程之同步机制实际应用场景举例说明

    目录 一.举例银行转账 二.问题解决 三.总结 这次让我们来看看一个真实场景吧:银行转账 一.举例银行转账 假设现在有一个xuewei的账号里面有 100W. 然后有多个任务在转账,转入转出都是跟这个xuewei账号相关的. 而且这些任务发生是随机的. 我们先把上面的场景写成代码: xuewei_account = 100 # amount为负数即是转出金额 def transfer(money):     global xuewei_account     xuewei_account +=

  • Python线程指南详细介绍

    本文介绍了Python对于线程的支持,包括"学会"多线程编程需要掌握的基础以及Python两个线程标准库的完整介绍及使用示例. 注意:本文基于Python2.4完成,:如果看到不明白的词汇请记得百度谷歌或维基,whatever. 1. 线程基础 1.1. 线程状态 线程有5种状态,状态转换的过程如下图所示: 1.2. 线程同步(锁) 多线程的优势在于可以同时运行多个任务(至少感觉起来是这样).但是当线程需要共享数据时,可能存在数据不同步的问题.考虑这样一种情况:一个列表里所有元素都是0

  • Python线程之定位与销毁的实现

    背景 开工前我就觉得有什么不太对劲,感觉要背锅.这可不,上班第三天就捅锅了. 我们有个了不起的后台程序,可以动态加载模块,并以线程方式运行,通过这种形式实现插件的功能.而模块更新时候,后台程序自身不会退出,只会将模块对应的线程关闭.更新代码再启动,6 得不行. 于是乎我就写了个模块准备大展身手,结果忘记写退出函数了,导致每次更新模块都新创建一个线程,除非重启那个程序,否则那些线程就一直苟活着. 这可不行啊,得想个办法清理呀,要不然怕是要炸了. 那么怎么清理呢?我能想到的就是两步走: 找出需要清理

  • Python线程指南分享

    本文介绍了Python对于线程的支持,包括"学会"多线程编程需要掌握的基础以及Python两个线程标准库的完整介绍及使用示例. 注意:本文基于Python2.4完成,:如果看到不明白的词汇请记得百度谷歌或维基,whatever. 1. 线程基础 1.1. 线程状态 线程有5种状态,状态转换的过程如下图所示: thread_stat_simple 1.2. 线程同步(锁) 多线程的优势在于可以同时运行多个任务(至少感觉起来是这样).但是当线程需要共享数据时,可能存在数据不同步的问题.考虑

  • python 线程的五个状态

    当程序中包含多个线程时,CPU 不是一直被特定的线程霸占,而是轮流执行各个线程. 那么,CPU 在轮换执行线程的过程中,即从创建到消亡的整个过程,可能会历经 5 种状态,分别是新建.就绪.运行.阻塞和死亡. 线程的新建状态 无论是通过 Thread 类直接实例化对象创建线程,还是通过继承自 Thread 类的子类实例化创建线程,新创建的线程在调用 start() 方法之前,不会得到执行,此阶段的线程就处于新建状态. 线程的就绪状态 当位于新建状态的线程调用 start() 方法后,该线程就转换到

  • Python线程之线程安全的队列Queue

    目录 一.什么是队列? 二.队列基操入队/出队/查队列状态 三.Queue是一个线程安全的类 一.什么是队列? 像排队一样,从头到尾排成一排,还可以有人继续往后排队,这就是队列. 这里学委想说的是Queue这个类, 它是queue这个内置模块内的一个类. import queue q = queue.Queue(5) #可以传入参数指定队列大小 queue.Queue()# 不传或者给0或者<0的数字则创建一个无限长度的队列 它提供了很多函数,下面几个函数,我们使用的比较多: get: 获取并移

  • Python线程之认识线程安全 

    目录 一.什么是线程安全? 二.在Python中有哪些类是线程安全的? 三.如何做到真正线程安全? 1.无状态函数 2.另一种化繁为简 一.什么是线程安全? 线程安全,名字就非常直接,在多线程情况下是安全的,多线程操作上的安全. 比如一个计算加法的函数,不管是一千个还是一万个线程,我们希望它执行的结果总是正确的,1+1 必须永远等于2, 而不是线程少的时候1+1 变成3或者4了. 通常我们都用线程安全来修饰一个类,修饰一个函数: 我们会说我设计的这个类是线程安全的这意味着,在多线程环境下,同时调

随机推荐