python並發請求
A. python進程之並行與並發的區別
並行 :
當系統有一個以上CPU時,則進程的操作有可能非並發。當一個CPU執行一個進程時,另一個CPU可以執行另一個進程,兩個進程互不搶佔CPU資源,可以同時進行,這種方式我們稱之為並行。
並發 :
當有多個進程在操作時,如果系統只有一個CPU,則它根本不可能真正同時執行一個以上的進程,它只能把CPU運行時間劃分成若干個時間段,再將時間 段分配給各個進程執行,在一個時間段的進程代碼運行時,其它進程處於掛起狀,這種方式我們稱之為並發。
區別:
並發和並行是即相似又有區別的兩個概念,並行是指兩個或者多個事件在同一時刻同時執行,而並發是指兩個或多個事件通過時間片輪流被執行。在多道程序環境下,並發性是指在一段時間內宏觀上有多個程序在同時運行,但在單核CPU中,同一時刻僅能有一道程序執行,故微觀上這些程序只能是分時地交替執行。倘若在計算機中有多個CPU,則這些可以並發執行的程序便可被分配到多個處理機上,實現並行執行,即利用每個處理機來處理一個可並發執行的程序,這樣,多個程序便可以同時執行。
相關推薦:《Python視頻教程》
進程的狀態如下圖所示
在了解其他概念之前,我們首先要了解進程的幾個狀態。在程序運行的過程中,由於被操作系統的調度演算法控制,程序會進入幾個狀態:就緒,運行和阻塞。
(1)就緒(Ready)狀態
當進程已分配到除CPU以外的所有必要的資源,只要獲得處理機便可立即執行,這時的進程狀態稱為就緒狀態。
(2)執行/運行(Running)狀態當進程已獲得處理機,其程序正在處理機上執行,此時的進程狀態稱為執行狀態。
(3)阻塞(Blocked)狀態正在執行的進程,由於等待某個事件發生而無法執行時,便放棄處理機而處於阻塞狀態。引起進程阻塞的事件可有多種,例如,等待I/O完成、申請緩沖區不能滿足、等待信件(信號)等。
相關推薦:
一文帶你讀懂Python中的進程
B. 如何用Python一門語言通吃高性能並發,GPU計算和深度學習
第一個就是並發本身所帶來的開銷即新開處理線程、關閉處理線程、多個處理線程時間片輪轉所帶來的開銷。
實際上對於一些邏輯不那麼復雜的場景來說這些開銷甚至比真正的處理邏輯部分代碼的開銷更大。所以我們決定採用基於協程的並發方式,即服務進程只有一個(單cpu)所有的請求數據都由這個服務進程內部來維護,同時服務進程自行調度不同請求的處理順序,這樣避免了傳統多線程並發方式新建、銷毀以及系統調度處理線程的開銷。基於這樣的考慮我們選擇了基於Tornado框架實現api服務的開發。Tornado的實現非常簡潔明了,使用python的生成器作為協程,利用IOLoop實現了調度隊列。
第二個問題是資料庫的性能,這里說的資料庫包括MongoDB和Redis,我這里分開講。
先講MongoDB的問題,MongoDB主要存儲不同的用戶對於驗證的不同設置,比如該顯示什麼樣的圖片。
一開始每次驗證請求都會查詢MongoDB,當時我們的MongoDB是純內存的,同時三台機器組成一個復制集,這樣的組合大概能穩定承載八九千的qps,後來隨著我們驗證量越來越大,這個承載能力逐漸就成為了我們的瓶頸。
為了徹底搞定這個問題,我們提出了最極端的解決方案,乾脆直接把資料庫中的數據完全緩存到服務進程里定期批量更新,這樣查詢的開銷將大大降低。但是因為我們用的是Python,由於GIL的存在,在8核伺服器上會fork出來8個服務進程,進程之間不像線程那麼方便,所以我們基於mmap自己寫了一套夥伴演算法構建了一個跨進程共享緩存。自從這套緩存上線之後,Mongodb的負載幾乎變成了零。
說完了MongoDB再說Redis的問題,Redis代碼簡潔、數據結構豐富、性能強大,唯一的問題是作為一個單進程程序,終究性能是有上限的。
雖然今年Redis發布了官方的集群版本,但是經過我們的測試,認為這套分布式方案的故障恢復時間不夠優秀並且運維成本較高。在Redis官方集群方案面世之前,開源世界有不少proxy方案,比如Twtter的TwemProxy和豌豆莢的Codis。這兩種方案測試完之後給我們的感覺TwemProxy運維還是比較麻煩,Codis使用起來讓人非常心曠神怡,無論是修改配置還是擴容都可以在配置頁面上完成,並且性能也還算不錯,但無奈當時Codis還有比較嚴重的BUG只能放棄之。
幾乎嘗試過各種方案之後,我們還是下決心自己實現一套分布式方案,目的是高度貼合我們的需求並且運維成本要低、擴容要方便、故障切換要快最重要的是數據冗餘一定要做好。
基於上面的考慮,我們確定基於客戶端的分布式方案,通過zookeeper來同步狀態保證高可用。具體來說,我們修改Redis源碼,使其向zookeeper注冊,客戶端由zookeeper上獲取Redis伺服器集群信息並根據統一的一致性哈希演算法來計算數據應該存儲在哪台Redis上,並在哈希環的下一台Redis上寫入一份冗餘數據,當讀取原始數據失敗時可以立即嘗試讀取冗餘數據而不會造成服務中斷。
C. python高並發怎麼解決
某個時間段內,數據涌來,這就是並發。如果數據量很大,就是高並發
高並發的解決方法:
1、隊列、緩沖區
假設只有一個窗口,陸續湧入食堂的人,排隊打菜是比較好的方式
所以,排隊(隊列)是一種天然解決並發的辦法
排隊就是把人排成 隊列,先進先出,解決了資源使用的問題
排成的隊列,其實就是一個緩沖地帶,就是 緩沖區
假設女生優先,每次都從這個隊伍中優先選出女生出來先打飯,這就是 優先隊列
例如queue模塊的類Queue、LifoQueue、PriorityQueue(小頂堆實現)
2、爭搶
只開一個窗口,有可能沒有秩序,也就是誰擠進去就給誰打飯
擠到窗口的人占據窗口,直到打到飯菜離開
其他人繼續爭搶,會有一個人占據著窗口,可以視為鎖定窗口,窗口就不能為其他人提供服務了。
這是一種鎖機制
誰搶到資源就上鎖,排他性的鎖,其他人只能等候
爭搶也是一種高並發解決方案,但是,這樣可能不好,因為有可能有人很長時間搶不到
3、預處理
如果排長隊的原因,是由於每個人打菜等候時間長,因為要吃的菜沒有,需要現做,沒打著飯不走開,鎖定著窗口
食堂可以提前統計大多數人最愛吃的菜品,將最愛吃的80%的熱門菜,提前做好,保證供應,20%的冷門菜,現做
這樣大多數人,就算鎖定窗口,也很快打到飯菜走了,快速釋放窗口
一種提前載入用戶需要的數據的思路,預處理 思想,緩存常用
更多Python知識,請關註:Python自學網!!
D. 如何使用Python實現並發編程
多線程幾乎是每一個程序猿在使用每一種語言時都會首先想到用於解決並發的工具(JS程序員請迴避),使用多線程可以有效的利用CPU資源(Python例外)。然而多線程所帶來的程序的復雜度也不可避免,尤其是對競爭資源的同步問題。
然而在python中由於使用了全局解釋鎖(GIL)的原因,代碼並不能同時在多核上並發的運行,也就是說,Python的多線程不能並發,很多人會發現使用多線程來改進自己的Python代碼後,程序的運行效率卻下降了,這是多麼蛋疼的一件事呀!如果想了解更多細節,推薦閱讀這篇文章。實際上使用多線程的編程模型是很困難的,程序員很容易犯錯,這並不是程序員的錯誤,因為並行思維是反人類的,我們大多數人的思維是串列(精神分裂不討論),而且馮諾依曼設計的計算機架構也是以順序執行為基礎的。所以如果你總是不能把你的多線程程序搞定,恭喜你,你是個思維正常的程序猿:)
Python提供兩組線程的介面,一組是thread模塊,提供基礎的,低等級(Low Level)介面,使用Function作為線程的運行體。還有一組是threading模塊,提供更容易使用的基於對象的介面(類似於Java),可以繼承Thread對象來實現線程,還提供了其它一些線程相關的對象,例如Timer,Lock
使用thread模塊的例子
import thread
def worker():
"""thread worker function"""
print 'Worker'
thread.start_new_thread(worker)
使用threading模塊的例子
import threading
def worker():
"""thread worker function"""
print 'Worker'
t = threading.Thread(target=worker)
t.start()
或者Java Style
import threading
class worker(threading.Thread):
def __init__(self):
pass
def run():
"""thread worker function"""
print 'Worker'
t = worker()
t.start()