Briefly describe the mutex in python multithreading

        In programming , in order to ensure the integrity of shared data operations, the concept of mutual exclusion locks is introduced . Each object corresponds to a tag that can be called a "mutex lock", which is used to ensure that only one thread can access the object at any one time . In python, due to the existence of multithreading and the possibility of global variable disorder when acting on global variables, methods such as synchronization and mutual exclusion are also added, but we mainly explain mutual exclusion locks:

The following code defines a global variable of my_num, and function sum1 and function sum2 both perform the operation of adding 1 to my_num, and both perform +1 million times. In the following code, we create two functions that execute two functions respectively. thread, then call start() to start the thread

import threading
import time

# Define global variable
 my_num = 0
 # Loop to add 1 to global variable each time
 def sum1 ():
     global my_num
     for i in range ( 1000000 ):


        my_num += 1
print("sum1:", my_num)
    


# Loop to add 1 to global variable
 def sum2 ():
     global my_num
     for i in range ( 1000000 ):
        my_num += 1
print("sum2:", my_num)
    


if __name__ == '__main__' :
     # Create two child threads
     first_thread = threading.Thread( target =sum1)
    second_thread = threading.Thread(target=sum2)

    # Start the thread to execute the corresponding task
     first_thread.start() # The main thread delays 1.5 seconds
     # time.sleep(1.5)
     # After the main thread waits for the first thread to complete, the code will continue to execute and start the second thread Execute tasks
     # first_thread.join() # Thread synchronization: execute one task in a predefined order to complete another task and then execute
     # print("The first thread is finished")
     second_thread.start()

The execution results are as follows:

sum1: 1239023
sum2: 1341576

Obviously, this result is not what we want. The result we want is that both function 1 and function 2 are executed 1 million times plus one, and the final result is to become 2 million. Of course, we can easily think of the reason for such a result. : When the global variable my_num is just equal to 1000 (some numbers, this is just an assumption), the two threads get the value of my_num at the same time, and each performs a +1 operation on him. At this time, it is obvious that the global my_num is only added 1 instead of +2 operation (not going into detail)

It is obvious that it is very convenient for multiple threads to share data of global variables in a process, and random modification of global variables may cause confusion of global variables, that is, multiple threads operate on a global variable at the same time, and there will be resource competition. problem, resulting in incorrect data results.

Similarly, in the following code we have added a mutex

Mutexes introduce a state for a resource: locked/unlocked

When a thread wants to change the shared data, it is locked first. At this time, the state of the resource is "locked", and other threads cannot change it; until the thread releases the resource and changes the state of the resource to "unlocked", other threads can Lock the resource again. Mutual exclusion locks ensure that only one thread writes at a time, thus ensuring the correctness of data in the case of multiple threads.

When a thread acquires the lock by calling the lock's acquire() method, the lock enters the "locked" state.

每次只有一个线程可以获得锁。如果此时另一个线程试图获得这个锁,该线程就会变为“blocked”状态,称为“阻塞”,直到拥有锁的线程调用锁的release()方法释放锁之后,锁进入“unlocked”状态。

线程调度程序从处于同步阻塞状态的线程中选择一个来获得锁,并使得该线程进入运行(running)状态。

import threading

# 定义全局变量
my_num = 0

# 创建互斥锁
lock = threading.Lock()

# def show():
#     print("哈哈")
# # 变量保存的是函数在内存中的地址,保存的函数引用
# a = show
# a()


# 循环给全局变量每次加上1
def sum1():
    # 上锁
    lock.acquire()
    global my_num
    for i in range(1000000):
        my_num += 1

    print("sum1:", my_num)
    # 释放锁
    lock.release()


# 循环给全局变量每次加上1
def sum2():
    # 上锁
    lock.acquire()
    global my_num
    for i in range(1000000):
        my_num += 1

    print("sum2:", my_num)
    # 释放锁
    lock.release()

if __name__ == '__main__':
    # 创建两个子线程
    first_thread = threading.Thread(target=sum1)
    second_thread = threading.Thread(target=sum2)

    # 启动线程执行对应的任务
    first_thread.start()
    second_thread.start()

    # 互斥锁:能保证统一时刻只有一个线程执行,那个线程抢到这个互斥锁我们决定不了,但是能保证数据最终不会有问题
    # 提示:加上互斥锁把多任务瞬间变成单任务,执行效率会下降。

可以看到最后的结果,加入互斥锁后,其结果与预期相符。

得到结果:

sum1: 1000000
sum2: 2000000

锁的好处:

  • 确保了某段关键代码只能由一个线程从头到尾完整地执行

锁的坏处:

  • 阻止了多线程并发执行,包含锁的某段代码实际上只能以单线程模式执行,效率就大大地下降了
  • 由于可以存在多个锁,不同的线程持有不同的锁,并试图获取对方持有的锁时,可能会造成死锁



Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325660097&siteId=291194637