手把手教你理解python3多线程【2】

版权声明:本文为博主原创文章,未经允许,不得转载,如需转载请注明出处 https://blog.csdn.net/ssjdoudou/article/details/83592276

写在最前面:写这篇博客的时候一直不能专心,因为今晚淘宝集能量我们和一个队杠上了,生死未卜

下面先看一个栗子:

import threading
import time


class ChangeMoney():
    def First(name):
        global money
        for i in range(100):
            money = money+1
            msg = "%s set money to " % name + str(money)
            print(msg)


    def Second(name):
        global money
        for i in range(100):
            money = money+1
            msg = "%s set money to " % name + str(money)
            print(msg)



    def Third(name):
        global money
        for i in range(100):
            money = money+1
            msg = "%s set money to " % name + str(money)
            print(msg)


money = 0
mutex = threading.Lock()

threads = []
t1 = threading.Thread(target=ChangeMoney.First,args=(u'First',))
threads.append(t1)
t2 = threading.Thread(target=ChangeMoney.Second,args=(u'Second',))
threads.append(t2)
t3 = threading.Thread(target=ChangeMoney.Third,args=(u'Third',))
threads.append(t3)

if __name__ == '__main__':
    for t in threads:
        #t = ChangeMoney()
        t.start()
    '''for i in range(5):
        t = ChangeMoney()
        t.start()'''

我们定义了三个线程,同时操作Money这个全局变量,输出结果如下:

First set money to 1
First set money to 2
First set money to 3
First set money to 4
First set money to 5
First set money to 6
First set money to 7
First set money to 8
First set money to 9
First set money to 10
First set money to 11
First set money to 12
First set money to 13
First set money to 14
First set money to 15
First set money to 16
First set money to 17
First set money to 18
First set money to 19
First set money to 20
Second set money to 21
Second set money to 22
Second set money to 23
Second set money to 24
Second set money to 25
Second set money to 26
Second set money to 27
Third set money to 28
Third set money to 29
Third set money to 30
Third set money to 31
Second set money to 32
Second set money to 33
Second set money to 34
Second set money to 35
Second set money to 36
Second set money to 37
Second set money to 38
Third set money to 39
Third set money to 40
Third set money to 41
Third set money to 42
Third set money to 43
Third set money to 44
Second set money to 45
Second set money to 46
Second set money to 47
Second set money to 48
Second set money to 49
Second set money to 50
Third set money to 51
Third set money to 52
Third set money to 53
Third set money to 54
Third set money to 55
Third set money to 56
Third set money to 57
Third set money to 58
Third set money to 59
Third set money to 60

Process finished with exit code 0

可以看到不同线程操作顺序比较混乱,我看到有的博主给的代码可以使线程同时操作结果,像这样:

Thread-5 set num to 2
Thread-3 set num to 3
Thread-2 set num to 5
Thread-1 set num to 5
Thread-4 set num to 4

但是我跑他的代码并没有复现,这里我们姑且认为这么做是不安全的,于是我们引入锁的概念

当多个线程都修改某一个共享数据的时候,需要进行同步控制。

线程同步能够保证多个线程安全访问竞争资源,最简单的同步机制是引入互斥锁。互斥锁为资源引入一个状态:锁定/非锁定。某个线程要更改共享数据时,先将其锁定,此时资源的状态为“锁定”,其他线程不能更改;直到该线程释放资源,将资源的状态变成“非锁定”,其他的线程才能再次锁定该资源。互斥锁保证了每次只有一个线程进行写入操作,从而保证了多线程情况下数据的正确性。

加锁

import threading
import time


class ChangeMoney():
    def First(name):
        global money
        for i in range(100):
            if mutex.acquire():
                money = money+1
                msg = "%s set money to " % name + str(money)
                print(msg)
                mutex.release()


    def Second(name):
        global money
        for i in range(100):
            if mutex.acquire():
                money = money+1
                msg = "%s set money to " % name + str(money)
                print(msg)
                mutex.release()


    def Third(name):
        global money
        for i in range(100):
            if mutex.acquire():
                money = money+1
                msg = "%s set money to " % name + str(money)
                print(msg)
                mutex.release()


money = 0
mutex = threading.Lock()

threads = []
t1 = threading.Thread(target=ChangeMoney.First,args=(u'First',))
threads.append(t1)
t2 = threading.Thread(target=ChangeMoney.Second,args=(u'Second',))
threads.append(t2)
t3 = threading.Thread(target=ChangeMoney.Third,args=(u'Third',))
threads.append(t3)

if __name__ == '__main__':
    for t in threads:
        #t = ChangeMoney()
        t.start()

再看输出:

First set money to 1
First set money to 2
First set money to 3
First set money to 4
First set money to 5
First set money to 6
First set money to 7
First set money to 8
First set money to 9
First set money to 10
First set money to 11
First set money to 12
First set money to 13
First set money to 14
First set money to 15
First set money to 16
First set money to 17
First set money to 18
First set money to 19
First set money to 20
Second set money to 21
Second set money to 22
Second set money to 23
Second set money to 24
Second set money to 25
Second set money to 26
Second set money to 27
Second set money to 28
Second set money to 29
Second set money to 30
Second set money to 31
Second set money to 32
Second set money to 33
Second set money to 34
Second set money to 35
Second set money to 36
Second set money to 37
Second set money to 38
Second set money to 39
Second set money to 40
Third set money to 41
Third set money to 42
Third set money to 43
Third set money to 44
Third set money to 45
Third set money to 46
Third set money to 47
Third set money to 48
Third set money to 49
Third set money to 50
Third set money to 51
Third set money to 52
Third set money to 53
Third set money to 54
Third set money to 55
Third set money to 56
Third set money to 57
Third set money to 58
Third set money to 59
Third set money to 60

Process finished with exit code 0

这里我们加了锁以后,对于Money的操作就变得有序起来,目前是数据量较小的情况,一旦数据量变大,线程增多,会出现两个线程同时更改数据的情况,这样是不安全的。

当一个线程调用锁的acquire()方法获得锁时,锁就进入“locked”状态。每次只有一个线程可以获得锁。如果此时另一个线程试图获得这个锁,该线程就会变为“blocked”状态,称为“同步阻塞”。

直到拥有锁的线程调用锁的release()方法释放锁之后,锁进入“unlocked”状态。线程调度程序从处于同步阻塞状态的线程中选择一个来获得锁,并使得该线程进入运行(running)状态。

猜你喜欢

转载自blog.csdn.net/ssjdoudou/article/details/83592276