關于并發、并行、同步阻塞、異步非阻塞、線程、進程、協程等這些概念,單純通過文字恐怕很難有比較深刻的理解,本文就通過代碼一步步實現這些并發和異步編程,并進行比較。解釋器方面本文選擇python3,畢竟python3才是python的未來,并且python3用原生的庫實現協程已經非常方便了。
1、準備階段
下面為所有測試代碼所需要的包
#! python3# coding:utf-8import socketfrom concurrent import futuresfrom selectors import DefaultSelector,EVENT_WRITE,EVENT_READimport asyncioimport aiohttpimport timefrom time import ctime
在進行不同實現方式的比較時,實現場景就是在進行爬蟲開發的時候通過向對方網站發起一系列的http請求訪問,統計耗時來判斷實現方式的優劣,具體地,通過建立通信套接字,訪問新浪主頁,返回源碼,作為一次請求。先實現一個裝飾器用來統計函數的執行時間:
def tsfunc(func): def wrappedFunc(*args,**kargs): start = time.clock() action = func(*args,**kargs) time_delta = time.clock() - start print ('[{0}] {1}() called, time delta: {2}'.format(ctime(),func.__name__,time_delta)) return action return wrappedFunc
輸出的格式為:當前時間,調用的函數,函數的執行時間。
2、阻塞/非阻塞和同步/異步
這兩對概念不是很好區分,從定義上理解:
阻塞:在進行socket通信過程中,一個線程發起請求,如果當前請求沒有返回結果,則進入sleep狀態,期間線程掛起不能做其他操作,直到有返回結果,或者超時(如果設置超時的話)。
非阻塞:與阻塞相似,只不過在等待請求結果時,線程并不掛起而是進行其他操作,即在不能立刻得到結果之前,該函數不會阻掛起當前線程,而會立刻返回。
同步:同步和阻塞比較相似,但是二者并不是同一個概念,同步是指完成事件的邏輯,是指一件事完成之后,再完成第二件事,以此類推…
異步:異步和非阻塞比較類似,異步的概念和同步相對。當一個異步過程調用發出后,調用者不能立刻得到結果。實際處理這個調用的部件在完成后,通過狀態、通知和回調來通知調用者,實現異步的方式通俗講就是“等會再告訴你”。
1)阻塞方式
回到代碼上,首先實現阻塞方式的請求函數:
def blocking_way(): sock = socket.socket() sock.connect(('www.sina.com',80)) request = 'GET / HTTP/1.0/r/nHOST:www.sina.com/r/n/r/n' sock.send(request.encode('ascii')) response = b'' chunk = sock.recv(4096) while chunk: response += chunk chunk = sock.recv(4096) return response
測試線程、多進程和多線程
# 阻塞無并發@tsfuncdef sync_way(): res = [] for i in range(10): res.append(blocking_way()) return len(res)@tsfunc# 阻塞、多進程def process_way(): worker = 10 with futures.ProcessPoolExecutor(worker) as executor: futs = {executor.submit(blocking_way) for i in range(10)} return len([fut.result() for fut in futs])# 阻塞、多線程@tsfuncdef thread_way(): worker = 10 with futures.ThreadPoolExecutor(worker) as executor: futs = {executor.submit(blocking_way) for i in range(10)} return len([fut.result() for fut in futs])
新聞熱點
疑難解答