成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

說說 Python 里關于線程安全的那些事兒

安全 數據安全 后端
那什么情況下,訪問數據時是安全的?什么情況下,訪問數據是不安全的?如何知道你的代碼是否線程安全?要如何訪問數據才能保證數據的安全?本篇文章會一一回答你的問題。

在并發編程時,如果多個線程訪問同一資源,我們需要保證訪問的時候不會產生沖突,數據修改不會發生錯誤,這就是我們常說的線程安全 。

那什么情況下,訪問數據時是安全的?什么情況下,訪問數據是不安全的?如何知道你的代碼是否線程安全?要如何訪問數據才能保證數據的安全?

本篇文章會一一回答你的問題。

1. 線程不安全是怎樣的?

要搞清楚什么是線程安全,就要先了解線程不安全是什么樣的。

比如下面這段代碼,開啟兩個線程,對全局變量 number 各自增 10萬次,每次增量 1。

  1. from threading import Thread, Lock 
  2.  
  3. number = 0 
  4.  
  5. def target(): 
  6.     global number 
  7.     for _ in range(1000000): 
  8.         number += 1 
  9.  
  10. thread_01 = Thread(targettarget=target) 
  11. thread_02 = Thread(targettarget=target) 
  12. thread_01.start() 
  13. thread_02.start() 
  14.  
  15. thread_01.join() 
  16. thread_02.join() 
  17.  
  18. print(number) 

正常我們的預期輸出結果,一個線程自增100萬,兩個線程就自增 200 萬嘛,輸出肯定為 2000000 。

可事實卻并不是你想的那樣,不管你運行多少次,每次輸出的結果都會不一樣,而這些輸出結果都有一個特點是,都小于 200 萬。

以下是執行三次的結果

  1. 1459782 
  2. 1379891 
  3. 1432921 

這種現象就是線程不安全,究其根因,其實是我們的操作 number += 1 ,不是原子操作,才會導致的線程不安全。

2. 什么是原子操作?

原子操作(atomic operation),指不會被線程調度機制打斷的操作,這種操作一旦開始,就一直運行到結束,中間不會切換到其他線程。

它有點類似數據庫中的 事務。

在 Python 的官方文檔上,列出了一些常見原子操作

  1. L.append(x) 
  2. L1.extend(L2) 
  3. x = L[i] 
  4. x = L.pop() 
  5. L1[i:j] = L2 
  6. L.sort() 
  7. x = y 
  8. x.field = y 
  9. D[x] = y 
  10. D1.update(D2) 
  11. D.keys() 

而下面這些就不是原子操作

  1. ii = i+1 
  2. L.append(L[-1]) 
  3. L[i] = L[j] 
  4. D[x] = D[x] + 1 

像上面的我使用自增操作 number += 1,其實等價于 number = number + 1,可以看到這種可以拆分成多個步驟(先讀取相加再賦值),并不屬于原子操作。

這樣就導致多個線程同時讀取時,有可能讀取到同一個 number 值,讀取兩次,卻只加了一次,最終導致自增的次數小于預期。

當我們還是無法確定我們的代碼是否具有原子性的時候,可以嘗試通過 dis 模塊里的 dis 函數來查看

當我們執行這段代碼時,可以看到 number += 1 這一行代碼,由兩條字節碼實現。

  • BINARY_ADD :將兩個值相加
  • STORE_GLOBAL:將相加后的值重新賦值

每一條字節碼指令都是一個整體,無法分割,他實現的效果也就是我們所說的原子操作。

當一行代碼被分成多條字節碼指令的時候,就代表在線程線程切換時,有可能只執行了一條字節碼指令,此時若這行代碼里有被多個線程共享的變量或資源時,并且拆分的多條指令里有對于這個共享變量的寫操作,就會發生數據的沖突,導致數據的不準確。

為了對比,我們從上面列表的原子操作拿一個出來也來試試,是不是真如官網所說的原子操作。

這里我拿字典的 update 操作舉例,代碼和執行過程如下圖

從截圖里可以看到,info.update(new) 雖然也分為好幾個操作:

  • LOAD_GLOBAL:加載全局變量
  • LOAD_ATTR:加載屬性,獲取 update 方法
  • LOAD_FAST:加載 new 變量
  • CALL_FUNCTION:調用函數
  • POP_TOP:執行更新操作

但我們要知道真正會引導數據沖突的,其實不是讀操作,而是寫操作。

上面這么多字節碼指令,寫操作都只有一個(POP_TOP),因此字典的 update 方法是原子操作。

3. 實現人工原子操作

在多線程下,我們并不能保證我們的代碼都具有原子性,因此如何讓我們的代碼變得具有 “原子性” ,就是一件很重要的事。

方法也很簡單,就是當你在訪問一個多線程間共享的資源時,加鎖可以實現類似原子操作的效果,一個代碼要嘛不執行,執行了的話就要執行完畢,才能接受線程的調度。

因此,我們使用加鎖的方法,對例子一進行一些修改,使其具備“原子性”。

  1. from threading import Thread, Lock 
  2.  
  3.  
  4. number = 0 
  5. lock = Lock() 
  6.  
  7.  
  8. def target(): 
  9.     global number 
  10.     for _ in range(1000000): 
  11.         with lock: 
  12.             number += 1 
  13.  
  14. thread_01 = Thread(targettarget=target) 
  15. thread_02 = Thread(targettarget=target) 
  16. thread_01.start() 
  17. thread_02.start() 
  18.  
  19. thread_01.join() 
  20. thread_02.join() 
  21.  
  22. print(number) 

此時,不管你執行多少遍,輸出都是 2000000.

4. 為什么 Queue 是線程安全的?

Python 的 threading 模塊里的消息通信機制主要有如下三種:

  • Event
  • Condition
  • Queue

使用最多的是 Queue,而我們都知道它是線程安全的。當我們對它進行寫入和提取的操作不會被中斷而導致錯誤,這也是我們在使用隊列時,不需要額外加鎖的原因。

他是如何做到的呢?

其根本原因就是 Queue 實現了鎖原語,因此他能像第三節那樣實現人工原子操作。

原語指由若干個機器指令構成的完成某種特定功能的一段程序,具有不可分割性;即原語的執行必須是連續的,在執行過程中不允許被中斷。

 

責任編輯:趙寧寧 來源: Python編程時光
相關推薦

2020-05-07 10:05:52

Python數據安全

2020-05-14 10:08:14

網絡安全網絡安全技術周刊

2019-12-27 10:28:07

信息安全證書信息安全網絡安全

2021-03-09 23:12:51

Python集合項目

2016-06-07 10:47:42

2019-11-20 10:00:56

開源侵權版權

2021-06-09 13:28:40

密碼安全身份認證數據安全

2022-08-04 10:18:32

棧遷移?寄存器內存

2013-07-09 13:50:05

2016-01-11 10:10:53

2017-04-12 12:31:14

緩存Web瀏覽器

2022-06-02 08:42:15

Redis數據庫

2014-02-14 09:28:55

數據中心日常維護

2017-03-31 09:24:53

AR現實游戲

2020-09-22 14:29:24

智能

2012-11-28 10:54:37

禁止追蹤DNT

2016-09-27 23:47:42

2014-05-30 10:23:15

樂跑手環智能手環運動手環

2018-03-01 15:34:20

數據科學面試招聘

2014-03-12 09:23:06

DevOps團隊合作
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 人操人人干人 | 91在线视频一区 | 亚洲视频中文字幕 | 欧美在线视频观看 | 日韩中文一区二区三区 | 中文字幕一区二区三 | 久久免费香蕉视频 | 色播视频在线观看 | 亚洲免费在线 | 欧美精品在线一区二区三区 | 99热热 | 国产香蕉视频 | 天天影视网天天综合色在线播放 | 理论片87福利理论电影 | 国产精品一区二区av | 中文字幕男人的天堂 | 亚洲精品久久久久中文字幕欢迎你 | 国产黄色精品在线观看 | 中文一区二区视频 | 黑人巨大精品欧美一区二区一视频 | 中文字幕一区二区在线观看 | av性色全交蜜桃成熟时 | 婷婷色在线播放 | 在线观看免费黄色片 | 欧美a级网站| 在线观看你懂的网站 | 国产视频一区二区 | 中文字幕久久精品 | 日韩影院在线观看 | 特黄特色大片免费视频观看 | 另类亚洲视频 | 国产午夜精品久久久久免费视高清 | 欧美视频免费 | 国产在线网址 | 日韩在线一区二区 | 中文字幕丁香5月 | 精品国产一区二区三区性色av | 午夜看电影在线观看 | 97精品久久 | 五月天婷婷丁香 | 欧美9999 |