多线程开发可能遇到的问题
假设两个线程t1和t2都要对num=0进行增1运算,t1和t2都各对num修改1000000次,num的最终的结果应该为2000000。但是由于是多线程访问,有可能出现下面情况:
from threading import Thread import time num = 0 def test1(): global num for i in range(1000000): num += 1 print("--test1--num=%d" % num) def test2(): global num for i in range(1000000): num += 1 print("--test2--num=%d" % num) if __name__ == '__main__': Thread(target=test1).start() Thread(target=test2).start() print("num = %d" % num) """ num = 134116 --test1--num=1032814 --test2--num=1166243 """
运行结果可能不一样,但是结果往往不是2000000。问题产生的原因就是没有控制多个线程对同一资源的访问,对数据造成破坏,使得线程运行的结果不可预期。这种现象称为“线程不安全”。
线程同步——使用互斥锁
如果多个线程共同对某个数据修改,则可能出现不可预料的结果,为了保证数据的正确性,需要对多个线程进行同步。
使用 Thread 对象的 Lock 和 Rlock 可以实现简单的线程同步,这两个对象都有 acquire 方法和 release 方法,对于那些需要每次只允许一个线程操作的数据,可以将其操作放到 acquire 和 release 方法之间。
使用互斥锁实现上面的例子:
from threading import Thread, Lock import time num = 0 def test1(): global num # 上锁 mutex.acquire() for i in range(1000000): num += 1 # 解锁 mutex.release() print("--test1--num=%d" % num) def test2(): global num mutex.acquire() for i in range(1000000): num += 1 mutex.release() print("--test2--num=%d" % num) start_time = time.time() # 开始时间 # 创建一把互斥锁,默认没有上锁 mutex = Lock() p1 = Thread(target=test1) p1.start() # time.sleep(3) # 取消屏蔽之后 再次运行程序,结果会不一样,,,为啥呢? p2 = Thread(target=test2) p2.start() p1.join() p2.join() end_time = time.time() # 结束时间 print("num = %d" % num) print("运行时间:%fs" % (end_time - start_time)) # 结束时间-开始时间 """ 输出结果: --test1--num=1000000 --test2--num=2000000 num = 2000000 运行时间:0.287206s """
同步的应用——多个线程有序执行
from threading import Lock, Thread from time import sleep class Tas<span>本文来源gaodai#ma#com搞*!代#%^码$网*</span>k1(Thread): def run(self): while True: # 判断是否上锁成功,返回值为bool类型 if lock1.acquire(): print("--task1--") sleep(0.5) lock2.release() class Task2(Thread): def run(self): while True: if lock2.acquire(): print("--task2--") sleep(0.5) lock3.release() class Task3(Thread): def run(self): while True: if lock3.acquire(): print("--task3--") sleep(0.5) lock1.release() if __name__ == '__main__': # 创建一把锁 lock1 = Lock() # 创建一把锁,并且锁上 lock2 = Lock() lock2.acquire() # 创建一把锁,并且锁上 lock3 = Lock() lock3.acquire() t1 = Task1() t2 = Task2() t3 = Task3() t1.start() t2.start() t3.start() """ --task1-- --task2-- --task3-- --task1-- --task2-- --task3-- --task1-- --task2-- ... """
生产者与消费者模式
为什么要使用生产者和消费者模式