python advanced multi thread handling of the same global variable

  • 2021-01-25 07:45:32
  • OfStack

In general:


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

Output results:


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

# Because multithreading is not like multiprocess 1, where each process has a separate resource block, threads share one resource block of the main thread (although this is not appropriate).

# Although this facilitates the data transfer between threads, the final result is not the correct output result due to the uncertainty of execution order between threads.

# For example, the following routine, if the global_flag flag global variable is not added, would appear, even though logically the final result is 2000000 (the number chosen is so large because the # problem is more obvious).

# But in fact, this is not the result, but a result less than 2 million, but occasionally 2 million will appear, this is an extremely ideal result, why?

# Mainly due to the order in which threads are called by cpu. Specifically, when the main thread creates two child threads, t1 and t2, they refer to func1() and func2(), respectively.

global_num += 1. global_num += 1. global_num += 1. global_num += 1. global_num += 1. The second procedure is to pay the sum to global_num, at which point the value of global_num will be updated. This occurs during program execution

# When cpu is executing a statement from t1 to the summing statement, it stops at the end of the first process and throws the thread t1 instead of t2. This also happens when the thread executes for a period of time

The second process of the summation statement has completed the initial assignment, so the whole summation in this period of time is equal to not done, so the final result is not 2000000 ## situation

# The solution to this situation is to add a variable and use "polling", but this is inefficient and waste ES46en, so we usually use "notification" to do it.

Polling method:


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

Running results:


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

Notification method:


from threading import Thread,Lock
 
 
global_num = 0
 
def func1():
	global global_num
	for i in range(1000000):
		lock.acquire()# The two threads will grab the lock at first, then lock it and execute the following programs. The other threads will execute in the listening state, waiting for this thread to unlock the lock and then grab the lock 
		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()

Output results:


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

Related articles: