一,多线程
1.我们有两个任务,如果没有多线程,我们得先完成任务1.再完成任务2,会非常耗时,如下:
def func1():
for i in range(10):
print("------{}----------任务1".format(i))
time.sleep(1)
def func2():
for i in range(10):
print("------{}----------任务2".format(i))
time.sleep(2)
start_time = time.time()
func1()
func2()
end_time = time.time()
print("最终耗时:{}".format(end_time-start_time))
#输出-------------------------------------
最终耗时:30.18034076690674
2.我们利用多线程来做,如下
#多线程
#threading模块
def func1():
for i in range(10):
print("------{}----------任务1".format(i))
time.sleep(1)
def func2():
for i in range(10):
print("------{}----------任务2".format(i))
time.sleep(2)
start_time = time.time()
th1 = threading.Thread(target=func1) #创建1个线程,传入任务1
th2 = threading.Thread(target=func2) #创建1个线程,传入任务2
th1.start() #启动线程1
th2.start() #启动线程2
th1.join() #在子线程1完成运行之前,主线程将一直等待
th2.join() #在子线程2完成运行之前,主线程将一直等待
end_time = time.time()
print("最终耗时:{}".format(end_time-start_time))
#输出---------------------------------------
最终耗时:20.086134433746338
可以看到,我们开启两个线程时间能节约三分之一,
二,自定义线程类
自定义线程,重写run方法,将任务写在run方法里,for循环实现多线程。
#自定义线程,重写run方法,将任务写在run方法里,for循环实现多线程。
class My_Thread(threading.Thread):
def __init__(self):
super().__init__()
def run(self):
for n in range(10):
print("------{}----------任务1".format(n))
time.sleep(1)
for i in range(3):
i = My_Thread()
i.start()
i.join()
三,多线程共享全局变量问题
1.当两个线程共用一个全局变量,结果就会发生bug,那是因为主要的代码a += 1在没有执行完成时,就切换了线程,例如:func1拿到a=100时没有执行计算就切换了线程2,此时func2将a加到了400切换会func1,此时a应该等于400,但是func1是之前拿到a=100,然后在100的基础上再进行加和,所以结果就不准确。
a = 0
def func1():
global a
for i in range(1000000):
a += 1
print(a)
def func2():
global a
for i in range(1000000):
a += 1
print(a)
th1 = threading.Thread(target=func1) #创建1个线程,传入任务1
th2 = threading.Thread(target=func2) #创建1个线程,传入任务2
th1.start() #启动线程1
th2.start() #启动线程2
th1.join() #在子线程1完成运行之前,主线程将一直等待
th2.join() #在子线程2完成运行之前,主线程将一直等待
#输出----------------------------------
1314387
1637562
如上代码,结果应该是2000000,但是却少了很多,为了解决这个问题,引入了锁的概率
四,互斥锁
threading模块里面有lock类,可以创建一把锁,在执行到关键代码处,加锁,在这把锁没有释放之前,不会切换其他线程,这就解决了前面的多线程共享全局变量问题。
a = 0
lock = threading.Lock() #创建一把锁
def func1():
global a
for i in range(1000000):
lock.acquire() #修改前加一把锁
a += 1
lock.release() #修改完释放锁
print(a)
def func2():
global a
for i in range(1000000):
lock.acquire() # 修改前加一把锁
a += 1
lock.release() # 修改完释放锁
print(a)
th1 = threading.Thread(target=func1) #创建1个线程,传入任务1
th2 = threading.Thread(target=func2) #创建1个线程,传入任务2
th1.start() #启动线程1
th2.start() #启动线程2
th1.join() #在子线程1完成运行之前,主线程将一直等待
th2.join() #在子线程2完成运行之前,主线程将一直等待
#输出-------------------------------------
1808484
2000000
如上代码,加锁之后结果是正确的2000000.
五,死锁
如下,创建两把锁,两个任务中a等b,b等a,程序无法运行,就造成了死锁的问题,所以我们在用锁的时候一定要小新,因为很难发现这个问题。
a = 0
lock_a = threading.Lock() #创建一把锁
lock_b = threading.Lock() #创建一把锁
def func1():
global a
for i in range(1000000):
lock_a.acquire() #修改前加一把锁
lock_b.acquire()
a += 1
lock_b.release() #修改完释放锁
lock_a.release()
print(a)
def func2():
global a
for i in range(1000000):
lock_b.acquire() # 修改前加一把锁
lock_a.acquire()
a += 1
lock_a.release() # 修改完释放锁
lock_b.release()
print(a)