Python多任务学习笔记(3)——多线程共享全局变量及可能产生的问题

1. 多线程共享全局变量验证

多线程通常用来完成多任务,但多任务之间通常需要共享数据(比如:一条子线程修改,一条子线程读取)。那么自然会有这样的问题:主线程内的多条子线程是否共享全局变量。

首先运行下述代码,观察输出:

import threading
# 定义一个全局变量
global_num = 100


def test1():
    global global_num
    global_num += 1
    print("Inside the Thread Denoted by "
          "Function test1() num = %d" % global_num)


def test2():
    print("Inside the Thread Denoted by "
          "Function test2() num = %d" % global_num)


def main():
    thread1 = threading.Thread(target=test1)
    thread2 = threading.Thread(target=test2)
    thread1.start()
    thread2.start()

    print("Inside the Main Thread num = %d" % global_num)


if __name__ == "__main__":
    main()

上述代码的运行结果为:

Inside the Thread Denoted by Function test1() num = 101
Inside the Thread Denoted by Function test2() num = 101
Inside the Main Thread num = 101

所以,Python中,主线程内的多条子线程共享全局变量

2. 多线程共享全局变量的资源竞争

2.1 资源竞争问题描述

首先,下面的代码希望实现这样一个功能:定义一个全局变量,通过两个线程分别对该变量进行累加1000000次,希望最后实现该全局变量值为2000000,请运行下述代码,观察其结果是否和你想象的一致。

import threading
import time

# 定义一个全局变量
global_num = 0


def test1(num):
    global global_num
    for i in range(num):
        global_num += 1
    print("Inside the Thread Denoted by "
          "Function test1() num = %d" % global_num)


def test2(num):
    global global_num
    for i in range(num):
        global_num += 1
    print("Inside the Thread Denoted by "
          "Function test2() num = %d" % global_num)


def main():
    thread1 = threading.Thread(target=test1, args=(1000000,))
    thread2 = threading.Thread(target=test2, args=(1000000,))
    thread1.start()
    thread2.start()

    # 等待两个线程均运行结束
    time.sleep(5)

    print("Inside the Main Thread num = %d" % global_num)


if __name__ == "__main__":
    main()

上述代码的运行结果为:

Inside the Thread Denoted by Function test1() num = 1356018
Inside the Thread Denoted by Function test2() num = 1470161
Inside the Main Thread num = 1470161

上述结果表明,最终运行输出并非我们所想要的2000000,但是原因何在?

2.2 资源竞争产生原因

因为最后变量global_num并未按照期望增加至2000000,所以问题必然出现在语句global_num += 1处。

实际上,之所以产生意料之外的结果,原因在于:如上图所示,虽然计算机看起来通过两条线程同时分别执行一个任务,但是:

  • 语句global_num += 1在被CPU执行前会被解释器编译为多条语句,如图中的3条语句,这才是CPU执行的原子级语句;
  • CPU通过时间片轮转的方式分别执行两条线程的原子语句。

基于上述两条原因,让我们分析一种情况,尝试解释为什么会出现上述意料之外的情形:

  • 线程1的两条原子语句(1.CPU获取global_num的值;2.CPU将global_num的值加1)得到执行后,CPU暂停执行该线程,并执行线程2;
  • 线程2的两条原子语句(1.CPU获取global_num的值;2.CPU将global_num的值加1)得到执行后,CPU暂停执行该线程,重新执行线程1的一条原子语句(3.将第2步的结果存储到global_num中);
  • 线程2的一条原子语句(3.将第2步的结果存储到global_num中)得到CPU执行。

通过对上述情形的分析,可以发现虽然CPU执行了两次global_num += 1语句,但是最终变量global_num的值只被增加了1。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值