python进阶之多线程对同一个全局变量的处理方法
作者:Jonny0318 发布时间:2023-09-29 19:03:58
通常情况下:
from threading import Thread
global_num = 0
def func1():
global global_num
for i in range(1000000):
global_num += 1
print('---------func1:global_num=%s--------'%global_num)
def func2():
global global_num
for i in range(1000000):
global_num += 1
print('--------fun2:global_num=%s'%global_num)
print('global_num=%s'%global_num)
lock = Lock()
t1 = Thread(target=func1)
t1.start()
t2 = Thread(target=func2)
t2.start()
输出结果:
global_num=0
---------func1:global_num=1492752--------
--------fun2:global_num=1515462
#由于多线程不像多进程一样,每一个进程都一个独立的资源块,线程之间是共享主线程的一个资源块(虽然这样说不合适)
#这样虽然方便了线程之间的数据传递,但是又会由于线程之间执行顺序的不确定,导致最后的结果不是应该输出的正确结果。
#例如下面的例程,如果没有添加global_flag标志全局变量,就会出现,虽然逻辑上最后的结果是2000000(之所以选择这么大的一个数,是因为可以更明显的看出#这个问题),
#但是实际上并不是这个结果,而是一个小于2000000的结果,但是不排出偶然会出现2000000,这是一个极为理想的结果,这是为什么呢?
#主要还是由于线程被cpu调用的顺序不确定。具体来讲就是当主线程创建出两个子线程,分别是t1和t2,他们有分别指向func1()和func2()。
#在这两个线程中的函数中,都有一句“global_num += 1”,在计算机内部cpu执行时,这一条语句实际上是两个过程:第一个过程是从内存中读取global_num的值,完成加一操作,这个时候global_num的值还是原来的值;第二个过程是将求和的值付给global_num,这时候global_num的值才会更新。在程序执行过程中会出现这种
#情况:当cpu在执行线程t1中的语句到求和那条语句时,在执行完第一个过程停了下来,将线程t1抛出,转而执行线程t2,当线程执行一段时间后也出现这中情况
#有转而执行线程t1,这时,正好执行求和语句的第二个过程,完成最初的赋值,那么这一段时间内的整个求和就等于没做,所以出现这中最后结果不是2000000的##情况
#解决这种情况可以利用添加一个变量,利用“轮询”的方式执行,但是这样做的效率很低,而且还浪费cpu,所以一般采用“通知”方式来做。
轮询方式:
from threading import Thread
global_num = 0
global_flag = 0
def func1():
global global_num
global global_flag
if global_flag == 0:
for i in range(1000000):
global_num += 1
global_flag = 1
print('---------func1:global_num=%s--------'%global_num)
def func2():
global global_num
while True:
if global_flag != 0:
for i in range(1000000):
global_num += 1
break
print('--------fun2:global_num=%s'%global_num)
print('global_num=%s'%global_num)
t1 = Thread(target=func1)
t1.start()
t2 = Thread(target=func2)
t2.start()
运行结果:
global_num=0
---------func1:global_num=1000000--------
--------fun2:global_num=2000000
通知方式:
from threading import Thread,Lock
global_num = 0
def func1():
global global_num
for i in range(1000000):
lock.acquire()#两个线程会最开始抢这个锁,拿到锁就会处于关锁,执行后面的程序,其他线程执行处于监听状态,等待这个线程开锁,再抢锁
global_num += 1
lock.release()
print('---------func1:global_num=%s--------'%global_num)
def func2():
global global_num
for i in range(1000000):
lock.acquire()
global_num += 1
lock.release()
print('--------fun2:global_num=%s'%global_num)
print('global_num=%s'%global_num)
lock = Lock()
t1 = Thread(target=func1)
t1.start()
t2 = Thread(target=func2)
t2.start()
输出结果:
global_num=0
---------func1:global_num=1901175--------
--------fun2:global_num=2000000
来源:https://blog.csdn.net/m0_37338590/article/details/78481671


猜你喜欢
- 本文实例讲述了mysql存储过程原理与使用方法。分享给大家供大家参考,具体如下:存储过程包含了一系列可执行的sql语句,存储过程存放于MyS
- 本文实例讲述了python对url格式解析的方法。分享给大家供大家参考。具体分析如下:python针对url格式的解析,可根据指定的完整UR
- 背景介绍作为一款产品,往往希望能得到用户的反馈,从而通过对用户行为的分析进行功能、交互等方面的改进。然而直接的一对一的用户交流是低效且困难的
- map()是一个 Python 内建函数,它允许你不需要使用循环就可以编写简洁的代码。一、Python map() 函数这个map()函数采
- 如下所示:from osgeo import gdalimport numpy as npdef read_tiff(inpath): &n
- numpy.linalg.norm函数的使用1、linalg = linear(线性)+ algebra(代数),norm则表示范数。首先需
- 1) 使用字典dict()循环遍历出一个可迭代对象中的元素,如果字典没有该元素,那么就让该元素作为字典的键,并将该键赋值为1,如果存在就将该
- 01直接生成这类方法是利用基本程序软件包numpy的随机数产生方法来生成各类用于聚类算法数据集合,也是自行制作轮子的生成方法。一、基础类型1
- 首先,运行 Python 解释器,导入 re 模块并编译一个 RE:#!python Python 2.2.2 (#1, Feb 10 20
- 本文实例讲述了Python排序搜索基本算法之选择排序。分享给大家供大家参考,具体如下:选择排序就是第n次把序列中最小的元素排在第n的位置上,
- 安装报错类型,解决方案;1. 数据库连接报错mysqldb只支持python2,pymysql支持3,都是使用c写的驱动,性能更好# dja
- 简单实现平面的点K均值分析,使用欧几里得距离,并用pylab展示。import pylab as pl#calc Euclid squire
- PS笔刷,样式,形状、渐变、滤镜载入方式及使用:1、笔刷载入方式: 打开PS,编辑-->预设管理器-->载入-->然后点你
- 1、构建合理的HTTP请求标头。HTTP的请求头是一组属性和配置信息,当您发送一个请求到网络服务器时。因为浏览器和Python爬虫发送的请求
- 前言在Selenium自动化测试过程中会遇到定位浏览器弹窗的情况,根据弹窗实现原理不同大致可分为以下几种定位方式。1. alert
- php服务端与客户端交互、提供开放api时,通常需要对敏感的部分api数据传输进行数据加密,这时候rsa非对称加密就能派上用处了,下面通过一
- 安装:cnpm i -S jwt-decode引入:import jwt_decode from "jwt-decode"
- 之前做了一个淘宝客返利微信公众号,后来很多人提到过微信返利机器人,现在微信助手开发好了,可以通过微信助手接口功能实现微信返利机器人。流程如下
- 六步安装Mysql(免安装包的才可以选安装位置),供大家参考,具体内容如下第一步:下载MySQL压缩包mysql下载路径直接点击链接也可以下
- 01 InnoDB ReplicaSet(副本集)介绍 在MySQL8.0引入了InnoD