python进阶之多线程对同一个全局变量的处理方法


Posted in Python onNovember 09, 2018

通常情况下:

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

以上这篇python进阶之多线程对同一个全局变量的处理方法就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Python 相关文章推荐
在Django框架中伪造捕捉到的URLconf值的方法
Jul 18 Python
git使用.gitignore设置不生效或不起作用问题的解决方法
Jun 01 Python
Python实现的密码强度检测器示例
Aug 23 Python
Python内存管理方式和垃圾回收算法解析
Nov 11 Python
详细解读tornado协程(coroutine)原理
Jan 15 Python
python 定义给定初值或长度的list方法
Jun 23 Python
在Pycharm中将pyinstaller加入External Tools的方法
Jan 16 Python
利用ctypes获取numpy数组的指针方法
Feb 12 Python
Python面向对象之类的封装操作示例
Jun 08 Python
Python全面分析系统的时域特性和频率域特性
Feb 26 Python
keras.utils.to_categorical和one hot格式解析
Jul 02 Python
浅谈Python数学建模之整数规划
Jun 23 Python
python 多线程将大文件分开下载后在合并的实例
Nov 09 #Python
python 利用for循环 保存多个图像或者文件的实例
Nov 09 #Python
浅谈python写入大量文件的问题
Nov 09 #Python
启动Atom并运行python文件的步骤
Nov 09 #Python
Python产生Gnuplot绘图数据的方法
Nov 09 #Python
python pyheatmap包绘制热力图
Nov 09 #Python
Django 视图层(view)的使用
Nov 09 #Python
You might like
第十节 抽象方法和抽象类 [10]
2006/10/09 PHP
php公用函数列表[正则]
2007/02/22 PHP
php页面消耗内存过大的处理办法
2013/03/18 PHP
php运行提示:Fatal error Allowed memory size内存不足的解决方法
2014/12/17 PHP
Yii2 assets清除缓存的方法
2016/05/16 PHP
Yii框架中jquery表单验证插件用法示例
2016/10/18 PHP
详解PHP版本兼容之openssl调用参数
2018/07/25 PHP
thinkphp5.1 框架钩子和行为用法实例分析
2020/05/25 PHP
javascript实现面向对象类的功能书写技巧
2010/03/07 Javascript
基于jquery循环map功能的代码
2011/02/26 Javascript
jQuery使用技巧简单汇总
2013/04/18 Javascript
浅析js预加载/延迟加载
2014/09/25 Javascript
JavaScript极简入门教程(二):对象和函数
2014/10/25 Javascript
javascript简单实现图片预加载
2014/12/03 Javascript
JavaScript创建一个object对象并操作对象属性的用法
2015/03/23 Javascript
js+css简单实现网页换肤效果
2015/12/29 Javascript
Base64(二进制)图片编码解析及在各种浏览器的兼容性处理
2017/02/09 Javascript
js 获取图像缩放后的实际宽高,位置等信息
2017/03/07 Javascript
nodejs实现简单的gulp打包
2017/12/21 NodeJs
解决vue打包项目后刷新404的问题
2018/03/06 Javascript
VUE在for循环里面根据内容值动态的加入class值的方法
2018/08/12 Javascript
js实现图片放大并跟随鼠标移动特效
2019/01/18 Javascript
详解新手使用vue-router传参时注意事项
2019/06/06 Javascript
vue修改Element的el-table样式的4种方法
2020/09/17 Javascript
Python使用ftplib实现简易FTP客户端的方法
2015/06/03 Python
python和bash统计CPU利用率的方法
2015/07/10 Python
使用python去除图片白色像素的实例
2019/12/12 Python
Python抓新型冠状病毒肺炎疫情数据并绘制全国疫情分布的代码实例
2020/02/05 Python
如何理解python面向对象编程
2020/06/01 Python
详解tensorflow之过拟合问题实战
2020/11/01 Python
HTML5边玩边学(1)画布实现方法
2010/09/21 HTML / CSS
Skip Hop官网:好莱坞宝宝挚爱品牌
2018/06/17 全球购物
Doyoueven官网:澳大利亚健身服饰和配饰品牌
2019/03/24 全球购物
乡镇防汛工作汇报
2014/10/28 职场文书
python保存大型 .mat 数据文件报错超出 IO 限制的操作
2021/05/10 Python
青岛市的收音机研制与生产
2022/04/07 无线电