溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

python中怎么利用多線程處理同一個(gè)全局變量

發(fā)布時(shí)間:2021-06-16 16:35:18 來(lái)源:億速云 閱讀:2181 作者:Leah 欄目:開(kāi)發(fā)技術(shù)

這篇文章將為大家詳細(xì)講解有關(guān)python中怎么利用多線程處理同一個(gè)全局變量,文章內(nèi)容質(zhì)量較高,因此小編分享給大家做個(gè)參考,希望大家閱讀完這篇文章后對(duì)相關(guān)知識(shí)有一定的了解。

通常情況下:

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()

輸出結(jié)果:

global_num=0
---------func1:global_num=1492752--------
--------fun2:global_num=1515462

#由于多線程不像多進(jìn)程一樣,每一個(gè)進(jìn)程都一個(gè)獨(dú)立的資源塊,線程之間是共享主線程的一個(gè)資源塊(雖然這樣說(shuō)不合適)

#這樣雖然方便了線程之間的數(shù)據(jù)傳遞,但是又會(huì)由于線程之間執(zhí)行順序的不確定,導(dǎo)致最后的結(jié)果不是應(yīng)該輸出的正確結(jié)果。

#例如下面的例程,如果沒(méi)有添加global_flag標(biāo)志全局變量,就會(huì)出現(xiàn),雖然邏輯上最后的結(jié)果是2000000(之所以選擇這么大的一個(gè)數(shù),是因?yàn)榭梢愿黠@的看出#這個(gè)問(wèn)題),

#但是實(shí)際上并不是這個(gè)結(jié)果,而是一個(gè)小于2000000的結(jié)果,但是不排出偶然會(huì)出現(xiàn)2000000,這是一個(gè)極為理想的結(jié)果,這是為什么呢?

#主要還是由于線程被cpu調(diào)用的順序不確定。具體來(lái)講就是當(dāng)主線程創(chuàng)建出兩個(gè)子線程,分別是t1和t2,他們有分別指向func1()和func2()。

#在這兩個(gè)線程中的函數(shù)中,都有一句“global_num += 1”,在計(jì)算機(jī)內(nèi)部cpu執(zhí)行時(shí),這一條語(yǔ)句實(shí)際上是兩個(gè)過(guò)程:第一個(gè)過(guò)程是從內(nèi)存中讀取global_num的值,完成加一操作,這個(gè)時(shí)候global_num的值還是原來(lái)的值;第二個(gè)過(guò)程是將求和的值付給global_num,這時(shí)候global_num的值才會(huì)更新。在程序執(zhí)行過(guò)程中會(huì)出現(xiàn)這種

#情況:當(dāng)cpu在執(zhí)行線程t1中的語(yǔ)句到求和那條語(yǔ)句時(shí),在執(zhí)行完第一個(gè)過(guò)程停了下來(lái),將線程t1拋出,轉(zhuǎn)而執(zhí)行線程t2,當(dāng)線程執(zhí)行一段時(shí)間后也出現(xiàn)這中情況

#有轉(zhuǎn)而執(zhí)行線程t1,這時(shí),正好執(zhí)行求和語(yǔ)句的第二個(gè)過(guò)程,完成最初的賦值,那么這一段時(shí)間內(nèi)的整個(gè)求和就等于沒(méi)做,所以出現(xiàn)這中最后結(jié)果不是2000000的##情況

#解決這種情況可以利用添加一個(gè)變量,利用“輪詢”的方式執(zhí)行,但是這樣做的效率很低,而且還浪費(fèi)cpu,所以一般采用“通知”方式來(lái)做。

輪詢方式:

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()

運(yùn)行結(jié)果:

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()#兩個(gè)線程會(huì)最開(kāi)始搶這個(gè)鎖,拿到鎖就會(huì)處于關(guān)鎖,執(zhí)行后面的程序,其他線程執(zhí)行處于監(jiān)聽(tīng)狀態(tài),等待這個(gè)線程開(kāi)鎖,再搶鎖
		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()

輸出結(jié)果:

global_num=0
---------func1:global_num=1901175--------
--------fun2:global_num=2000000

關(guān)于python中怎么利用多線程處理同一個(gè)全局變量就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,可以學(xué)到更多知識(shí)。如果覺(jué)得文章不錯(cuò),可以把它分享出去讓更多的人看到。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI