python多线程及锁

一,多线程

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)

你可能感兴趣的:(python,python,开发语言,后端)