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

 更新时间:2018年11月09日 09:36:26   作者:Jonny0318   我要评论

今天小编就为大家分享一篇python进阶之多线程对同一个全局变量的处理方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧

通常情况下:

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进程间通信之命名管道

    本篇文章主要介绍了详解Python进程间通信之命名管道,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-08-08
  • python处理圆角图片、圆形图片的例子

    python处理圆角图片、圆形图片的例子

    最近因为工作需要,需要处理图片,一种是头像的方形图片处理成圆行的,一种是方形图片的4角变得椭圆点
    2014-04-04
  • Python里隐藏的“禅”

    Python里隐藏的“禅”

    这篇文章主要介绍了IT柏拉图翻译的python的lib目录下this.py文件中的一首诗,蕴含了Python程序设计中很多哲理性的规律,需要的朋友可以参考下
    2014-06-06
  • Python中Collections模块的Counter容器类使用教程

    Python中Collections模块的Counter容器类使用教程

    Counter是Python标准库提供的一个非常有用的容器,可以用来对序列中出现的各个元素进行计数,下面就来一起看一下Python中Collections模块的Counter容器类使用教程
    2016-05-05
  • 从零学Python之入门(二)基本数据类型

    从零学Python之入门(二)基本数据类型

    这是继“hello world”之后的第二篇入门级基础知识,以后这个系列会按照入门、进阶、精通三个分类进行下去,欢迎高手们来拍砖
    2014-05-05
  • 基于windows下pip安装python模块时报错总结

    基于windows下pip安装python模块时报错总结

    今天小编就为大家分享一篇基于windows下pip安装python模块时报错总结,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-06-06
  • python版opencv摄像头人脸实时检测方法

    python版opencv摄像头人脸实时检测方法

    今天小编就为大家分享一篇python版opencv摄像头人脸实时检测方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-08-08
  • 重命名批处理python脚本

    重命名批处理python脚本

    师兄采集的视网膜图像放在一个文件夹下,由于分类十分混乱,因此出现了一个文件多次出现的情况,因此让我写了个脚本
    2013-04-04
  • Python金融数据可视化汇总

    Python金融数据可视化汇总

    这篇文章主要介绍了Python金融数据可视化(两列数据的提取,分别画,双坐标轴,双图,两种不同的图)等内容。
    2017-11-11
  • Python3.6 Schedule模块定时任务(实例讲解)

    Python3.6 Schedule模块定时任务(实例讲解)

    下面小编就为大家带来一篇Python3.6 Schedule模块定时任务(实例讲解)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-11-11

最新评论