浅谈Python中的线程锁
竞争条件是并发编程中的一个重要问题。当一个线程试图修改共享资源的同时,另一个线程正在修改该资源时,就会出现这种情况——这会导致输出乱码,这就是线程需要同步的原因。
Python的threading模块包括Lock作为同步工具。锁有两种状态:锁定解锁
可以使用该acquire()方法锁定锁。一旦一个线程获得了锁,所有后续的获取锁的尝试都会被阻塞,直到它被释放。可以使用该release()方法释放锁。
注意在未锁定状态的锁上调用该release()方法会导致错误。
以下代码通过一个简单的示例展示了如何在 Python 中使用锁:
假设银行账户中有 100 美元。每个月存入 10 美元作为利润,扣除 10 美元支付账单。thread1用于存入利润,而thread2用于支付账单。在某些月份,利润会在账单支付后存入。但是,这不应影响帐户中的最终金额。竞争条件
由于竞争条件下,以下代码得到的结果可能不正确。可能会出现一个线程在上下文切换前无法将更新后的值写入共享变量deposit,而另一个线程读取到未更新的值的情况;因此,导致不可预测的结果。# Importing the threading module import threading deposit = 100 # Function to add profit to the deposit def add_profit(): global deposit for i in range(100000): deposit = deposit + 10 # Function to deduct money from the deposit def pay_bill(): global deposit for i in range(100000): deposit = deposit - 10 # Creating threads thread1 = threading.Thread(target = add_profit, args = ()) thread2 = threading.Thread(target = pay_bill, args = ()) # Starting the threads thread1.start() thread2.start() # Waiting for both the threads to finish executing thread1.join() thread2.join() # Displaying the final value of the deposit print(deposit)
运行以上代码,将输出-235420使用锁来解决问题
acquire()和release()方法之间的代码是原子执行的,因此在另一个线程已经进行更改之后,一个线程不可能读取未更新的版本。# Importing the threading module import threading # Declraing a lock lock = threading.Lock() deposit = 100 # Function to add profit to the deposit def add_profit(): global deposit for i in range(100000): lock.acquire() deposit = deposit + 10 lock.release() # Function to deduct money from the deposit def pay_bill(): global deposit for i in range(100000): lock.acquire() deposit = deposit - 10 lock.release() # Creating threads thread1 = threading.Thread(target = add_profit, args = ()) thread2 = threading.Thread(target = pay_bill, args = ()) # Starting the threads thread1.start() thread2.start() # Waiting for both the threads to finish executing thread1.join() thread2.join() # Displaying the final value of the deposit print(deposit)
运行以上程序,将输出:100