真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

python線程互斥鎖Lock(29)

在前一篇文章?python線程創(chuàng)建和傳參?中我們介紹了關(guān)于python線程的一些簡單函數(shù)使用和線程的參數(shù)傳遞,使用多線程可以同時執(zhí)行多個任務(wù),提高開發(fā)效率,但是在實際開發(fā)中往往我們會碰到線程同步問題,假如有這樣一個場景:對全局變量累加1000000次,為了提高效率,我們可以使用多線程完成,示例代碼如下:

網(wǎng)站建設(shè)哪家好,找成都創(chuàng)新互聯(lián)!專注于網(wǎng)頁設(shè)計、網(wǎng)站建設(shè)、微信開發(fā)、小程序定制開發(fā)、集團(tuán)企業(yè)網(wǎng)站建設(shè)等服務(wù)項目。為回饋新老客戶創(chuàng)新互聯(lián)還提供了米林免費建站歡迎大家使用!

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

# !usr/bin/env python

# -*- coding:utf-8 _*-

"""

@Author:何以解憂

@Blog(個人博客地址): shuopython.com

@WeChat Official Account(微信公眾號):猿說python

@Github:www.github.com

@File:python_thread_lock.py

@Time:2019/10/17 21:22

?

@Motto:不積跬步無以至千里,不積小流無以成江海,程序人生的精彩需要堅持不懈地積累!

"""

# 導(dǎo)入線程threading模塊

importthreading

?

# 聲明全局變量

g_num=0

?

defmy_thread1():

?

????# 聲明全局變量

????globalg_num

????# 循環(huán) 1000000 次,每次累計加 1

????foriinrange(0,1000000):

????????g_num=g_num+1

?

defmy_thread2():

?

????# 聲明全局變量

????globalg_num

????# 循環(huán) 1000000 次,每次累計加 1

????foriinrange(0,1000000):

????????g_num=g_num+1

?

defmain(i):

?

????# 聲明全局變量

????globalg_num

????# 初始化全局變量,初始值為 0

????g_num=0

????# 創(chuàng)建兩個線程,對全局變量進(jìn)行累計加 1

????t1=threading.Thread(target=my_thread1)

????t2=threading.Thread(target=my_thread2)

?

????# 啟動線程

????t1.start()

????t2.start()

????# 阻塞函數(shù),等待線程結(jié)束

????t1.join()

????t2.join()

????# 獲取全局變量的值

????print("第%d次計算結(jié)果:%d "%(i,g_num))

?

if__name__=="__main__":

?

????# 循環(huán)4次,調(diào)用main函數(shù),計算全局變量的值

????foriinrange(1,5):

????????main(i)

輸出結(jié)果:

1

2

3

4

第1次計算結(jié)果:1262996

第2次計算結(jié)果:1661455

第3次計算結(jié)果:1300211

第4次計算結(jié)果:1563699

what ? 這是什么操作??看著代碼好像也沒問題,兩個線程,各自累加1000000次,不應(yīng)該輸出是2000000次嗎?而且調(diào)用了4次main函數(shù),每次輸出的結(jié)果還不同??!

?

python 線程互斥鎖Lock(29)

?

一.線程共享全局變量

分析下上面的代碼:兩個線程共享全局變量并執(zhí)行for循環(huán)1000000,每次自動加1,我們都知道兩個線程都是同時在運行,也就是說兩個線程同時在執(zhí)行 g_num = g_num + 1 操作, 經(jīng)過我們冷靜分析一波,貌似結(jié)果還是應(yīng)該等于2000000,對不對?

?

python 線程互斥鎖Lock(29)

?

首先,我們將上面全局變量自動加 1 的代碼分為兩步:

1

2

第一步:g_num+1

第二步:將g_num+1的結(jié)果賦值給g_num

由此可見,執(zhí)行一個完整的自動加1過程需要兩步,然而線程卻是在同時運行,誰也不能保證線程1的第一步和第二步執(zhí)行完成之后才執(zhí)行線程2的第一步和第二步,執(zhí)行的過程充滿隨機(jī)性,這就是導(dǎo)致每次計算結(jié)果不同的原因所在!

舉個簡單的例子:

假如當(dāng)前 g_num 值是100,當(dāng)線程1執(zhí)行第一步時,cpu通過計算獲得結(jié)果101,并準(zhǔn)備把計算的結(jié)果101賦值給g_num,然后再傳值的過程中,線程2突然開始執(zhí)行了并且執(zhí)行了第一步,此時g_num的值仍未100,101還在傳遞的過程中,還沒成功賦值,線程2獲得計算結(jié)果101,并準(zhǔn)備傳遞給g_num,經(jīng)過一來一去這么一折騰,分明做了兩次加 1 操作,g_num結(jié)果卻是101,誤差就由此產(chǎn)生,往往循環(huán)次數(shù)越多,產(chǎn)生的誤差就越大。

?

python 線程互斥鎖Lock(29)

?

二.線程互斥鎖

為了避免上述問題,我們可以利用線程互斥鎖解決這個問題。那么互斥鎖到底是個什么原理呢?互斥鎖就好比排隊上廁所,一個坑位只能蹲一個人,只有占用坑位的人完事了,另外一個人才能上!

python 線程互斥鎖Lock(29)

1.創(chuàng)建互斥鎖

導(dǎo)入線程模塊,通過?threading.Lock()?創(chuàng)建互斥鎖.

1

2

3

4

5

# 導(dǎo)入線程threading模塊

importthreading

?

# 創(chuàng)建互斥鎖

mutex=threading.Lock()

?

2.鎖定資源/解鎖資源

acquire()?— 鎖定資源,此時資源是鎖定狀態(tài),其他線程無法修改鎖定的資源,直到等待鎖定的資源釋放之后才能操作;

release()?— 釋放資源,也稱為解鎖操作,對鎖定的資源解鎖,解鎖之后其他線程可以對資源正常操作;

?

以上面的代碼為列子:想得到正確的結(jié)果,可以直接利用互斥鎖在全局變量 加1 之前 鎖定資源,然后在計算完成之后釋放資源,這樣就是一個完整的計算過程,至于應(yīng)該是哪個線程先執(zhí)行,無所謂,先到先得,憑本事說話….演示代碼如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

# !usr/bin/env python

# -*- coding:utf-8 _*-

"""

@Author:何以解憂

@Blog(個人博客地址): shuopython.com

@WeChat Official Account(微信公眾號):猿說python

@Github:www.github.com

@File:python_thread_lock.py

@Time:2019/10/18 21:22

?

@Motto:不積跬步無以至千里,不積小流無以成江海,程序人生的精彩需要堅持不懈地積累!

"""

# 導(dǎo)入線程threading模塊

importthreading

?

# 聲明全局變量

g_num=0

# 創(chuàng)建互斥鎖

mutex=threading.Lock()

?

defmy_thread1():

?

????# 聲明全局變量

????globalg_num

????# 循環(huán) 1000000 次,每次累計加 1

????foriinrange(0,1000000):

????????# 鎖定資源

????????mutex.acquire()

????????g_num=g_num+1

????????# 解鎖資源

????????mutex.release()

?

defmy_thread2():

?

????# 聲明全局變量

????globalg_num

????# 循環(huán) 1000000 次,每次累計加 1

????foriinrange(0,1000000):

????????# 鎖定資源

????????mutex.acquire()

????????g_num=g_num+1

????????# 解鎖資源

????????mutex.release()

?

defmain(i):

?

????# 聲明全局變量

????globalg_num

????# 初始化全局變量,初始值為 0

????g_num=0

????# 創(chuàng)建兩個線程,對全局變量進(jìn)行累計加 1

????t1=threading.Thread(target=my_thread1)

????t2=threading.Thread(target=my_thread2)

?

????# 啟動線程

????t1.start()

????t2.start()

????# 阻塞函數(shù),等待線程結(jié)束

????t1.join()

????t2.join()

????# 獲取全局變量的值

????print("第%d次計算結(jié)果:%d "%(i,g_num))

?

if__name__=="__main__":

?

????# 循環(huán)4次,調(diào)用main函數(shù),計算全局變量的值

????foriinrange(1,5):

????????main(i)

輸出結(jié)果:

1

2

3

4

第1次計算結(jié)果:2000000

第2次計算結(jié)果:2000000

第3次計算結(jié)果:2000000

第4次計算結(jié)果:2000000

由此可見,全局變量計算加上互斥鎖之后,不論執(zhí)行多少次,計算結(jié)果都相同。注意:互斥鎖一旦鎖定之后要記得解鎖,否則資源會一直處于鎖定狀態(tài);

?

三.線程死鎖

1.單個互斥鎖的死鎖:acquire()/release()?是成對出現(xiàn)的,互斥鎖對資源鎖定之后就一定要解鎖,否則資源會一直處于鎖定狀態(tài),其他線程無法修改;就好比上面的代碼,任何一個線程沒有釋放資源release(),程序就會一直處于阻塞狀態(tài)(在等待資源被釋放),不信你可以試一試~

2.多個互斥鎖的死鎖:在同時操作多個互斥鎖的時候一定要格外小心,因為一不小心就容易進(jìn)入死循環(huán),假如有這樣一個場景:boss讓程序員一實現(xiàn)功能一的開發(fā),讓程序員二實現(xiàn)功能二的開發(fā),功能開發(fā)完成之后一起整合代碼!

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

# 導(dǎo)入線程threading模塊

importthreading

# 導(dǎo)入線程time模塊

importtime

?

?

# 創(chuàng)建互斥鎖

mutex_one=threading.Lock()

mutex_two=threading.Lock()

?

defprogrammer_thread1():

?

????mutex_one.acquire()

????print("我是程序員1,module1開發(fā)正式開始,誰也別動我的代碼")

????time.sleep(2)

?

????# 此時會堵塞,因為這個mutex_two已經(jīng)被線程programmer_thread2搶先上鎖了,等待解鎖

????mutex_two.acquire()

????print("等待程序員2通知我合并代碼")

????mutex_two.release()

?

????mutex_one.release()

?

defprogrammer_thread2():

????mutex_two.acquire()

????print("我是程序員2,module2開發(fā)正式開始,誰也別動我的代碼")

????time.sleep(2)

?

????# 此時會堵塞,因為這個mutex_one已經(jīng)被線程programmer_thread1搶先上鎖了,等待解鎖

????mutex_one.acquire()

????print("等待程序員1通知我合并代碼")

????mutex_one.release()

?

????mutex_two.release()

?

defmain():

?

????t1=threading.Thread(target=programmer_thread1)

????t2=threading.Thread(target=programmer_thread2)

?

????# 啟動線程

????t1.start()

????t2.start()

????# 阻塞函數(shù),等待線程結(jié)束

????t1.join()

????t2.join()

????# 整合代碼結(jié)束

????print("整合代碼結(jié)束 ")

?

if__name__=="__main__":

?

????main()

輸出結(jié)果:

1

2

我是程序員1,module1開發(fā)正式開始,誰也別動我的代碼

我是程序員2,module2開發(fā)正式開始,誰也別動我的代碼

分析下上面代碼:程序員1在等程序員2通知,程序員2在等程序員1通知,兩個線程都陷入阻塞中,因為兩個線程都在等待對方解鎖,這就是死鎖!所以在開發(fā)中對于死鎖的問題還是需要多多注意!

?

四.重點總結(jié)

1.線程與線程之間共享全局變量需要設(shè)置互斥鎖;

2.注意在互斥鎖操作中?acquire()/release()?成對出現(xiàn),避免造成死鎖;

?

?

猜你喜歡:

1.python線程創(chuàng)建和傳參

2.python函數(shù)-缺省參數(shù)

3.python局部變量和全局變量

?

轉(zhuǎn)載請注明:猿說Python???Python線程互斥鎖Lock?


網(wǎng)站欄目:python線程互斥鎖Lock(29)
網(wǎng)站URL:http://weahome.cn/article/pogdco.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部