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 相关文章推荐
python中from module import * 的一个坑
Jul 20 Python
介绍Python的Django框架中的静态资源管理器django-pipeline
Apr 25 Python
日常整理python执行系统命令的常见方法(全)
Oct 22 Python
python中copy()与deepcopy()的区别小结
Aug 03 Python
python自动发邮件总结及实例说明【推荐】
May 31 Python
使用Pytorch来拟合函数方式
Jan 14 Python
python pprint模块中print()和pprint()两者的区别
Feb 10 Python
Python datetime 格式化 明天,昨天实例
Mar 02 Python
Python使用monkey.patch_all()解决协程阻塞问题
Apr 15 Python
解决pycharm debug时界面下方不出现step等按钮及变量值的问题
Jun 09 Python
python 下载文件的几种方式分享
Apr 07 Python
用Python写一个简易版弹球游戏
Apr 13 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
一步一步学习PHP(7) php 字符串相关应用
2010/03/05 PHP
php strrpos()与strripos()函数
2013/08/31 PHP
基于PHP实现假装商品限时抢购繁忙的效果
2015/10/16 PHP
在WordPress中安装使用视频播放器插件Hana Flv Player
2016/01/04 PHP
给大家分享几个常用的PHP函数
2017/01/15 PHP
yii 框架实现按天,月,年,自定义时间段统计数据的方法分析
2020/04/04 PHP
二级域名转向类
2006/11/09 Javascript
jquery选择器之层级过滤选择器详解
2014/01/27 Javascript
Javascript基础教程之break和continue语句
2015/01/18 Javascript
AngularJS中的Directive自定义一个表格
2016/01/25 Javascript
jQuery点击其他地方时菜单消失的实现方法
2016/04/22 Javascript
巧用Vue.js+Vuex制作专门收藏微信公众号的app
2016/11/03 Javascript
JS 判断某变量是否为某数组中的一个值的3种方法(总结)
2017/07/10 Javascript
简单的三步vuex入门
2018/05/20 Javascript
jQuery实现的记住帐号密码功能完整示例
2019/08/03 jQuery
Vue路由之JWT身份认证的实现方法
2019/08/26 Javascript
vue实现codemirror代码编辑器中的SQL代码格式化功能
2019/08/27 Javascript
优化Vue中date format的性能详解
2020/01/13 Javascript
JS图片预加载三种实现方法解析
2020/05/08 Javascript
跟老齐学Python之变量和参数
2014/10/10 Python
Django + Uwsgi + Nginx 实现生产环境部署的方法
2018/06/20 Python
解决pycharm 误删掉项目文件的处理方法
2018/10/22 Python
对python3中, print横向输出的方法详解
2019/01/28 Python
python判断一个对象是否可迭代的例子
2019/07/22 Python
Python TKinter如何自动关闭主窗口
2020/02/26 Python
Python多线程正确用法实例解析
2020/05/30 Python
Python Map 函数的使用
2020/08/28 Python
使用pandas实现筛选出指定列值所对应的行
2020/12/13 Python
用60行代码实现Python自动抢微信红包
2021/02/04 Python
matplotlib阶梯图的实现(step())
2021/03/02 Python
项目建议书范文
2014/05/12 职场文书
一份文言文检讨书
2014/09/13 职场文书
搞笑婚礼主持词开场白
2015/11/24 职场文书
幼儿园小班开学寄语(2016秋季)
2015/12/03 职场文书
演讲稿之感恩老师(三篇范文)
2019/09/06 职场文书
解决Mysql多行子查询的使用及空值问题
2022/01/22 MySQL