通過(guò)實(shí)例解析Python RPC實(shí)現(xiàn)原理及方法
單線程同步
- 使用socket傳輸數(shù)據(jù)
- 使用json序列化消息體
- struct將消息編碼為二進(jìn)制字節(jié)串,進(jìn)行網(wǎng)絡(luò)傳輸
消息協(xié)議
// 輸入 { in: "ping", params: "ireader 0" } // 輸出 { out: "pong", result: "ireader 0" }
客戶端 client.py
# coding: utf-8 # client.py import json import time import struct import socket def rpc(sock, in_, params): response = json.dumps({"in": in_, "params": params}) # 請(qǐng)求消息體 length_prefix = struct.pack("I", len(response)) # 請(qǐng)求長(zhǎng)度前綴 sock.sendall(length_prefix) sock.sendall(response) length_prefix = sock.recv(4) # 響應(yīng)長(zhǎng)度前綴 length, = struct.unpack("I", length_prefix) body = sock.recv(length) # 響應(yīng)消息體 response = json.loads(body) return response["out"], response["result"] # 返回響應(yīng)類型和結(jié)果 if __name__ == '__main__': s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(("localhost", 8080)) for i in range(10): # 連續(xù)發(fā)送10個(gè)rpc請(qǐng)求 out, result = rpc(s, "ping", "ireader %d" % i) print out, result time.sleep(1) # 休眠1s,便于觀察 s.close() # 關(guān)閉連接
服務(wù)端 blocking_single.py
# coding: utf8 # blocking_single.py import json import struct import socket def handle_conn(conn, addr, handlers): print addr, "comes" while True: # 循環(huán)讀寫(xiě) length_prefix = conn.recv(4) # 請(qǐng)求長(zhǎng)度前綴 if not length_prefix: # 連接關(guān)閉了 print addr, "bye" conn.close() break # 退出循環(huán),處理下一個(gè)連接 length, = struct.unpack("I", length_prefix) body = conn.recv(length) # 請(qǐng)求消息體 request = json.loads(body) in_ = request['in'] params = request['params'] print in_, params handler = handlers[in_] # 查找請(qǐng)求處理器 handler(conn, params) # 處理請(qǐng)求 def loop(sock, handlers): while True: conn, addr = sock.accept() # 接收連接 handle_conn(conn, addr, handlers) # 處理連接 def ping(conn, params): send_result(conn, "pong", params) def send_result(conn, out, result): response = json.dumps({"out": out, "result": result}) # 響應(yīng)消息體 length_prefix = struct.pack("I", len(response)) # 響應(yīng)長(zhǎng)度前綴 conn.sendall(length_prefix) conn.sendall(response) if __name__ == '__main__': sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 創(chuàng)建一個(gè)TCP套接字 sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # 打開(kāi)reuse addr選項(xiàng) sock.bind(("localhost", 8080)) # 綁定端口 sock.listen(1) # 監(jiān)聽(tīng)客戶端連接 handlers = { # 注冊(cè)請(qǐng)求處理器 "ping": ping } loop(sock, handlers) # 進(jìn)入服務(wù)循環(huán)
多線程同步
- 使用線程庫(kù)thread創(chuàng)建原生線程
- 服務(wù)器可并行處理多個(gè)客戶端
服務(wù)端 multithread.py
多進(jìn)程同步
- Python的GIL導(dǎo)致單個(gè)進(jìn)程只能占滿一個(gè)CPU核心,多線程無(wú)法利用多核優(yōu)勢(shì)
- os.fork()會(huì)生成子進(jìn)程
- 子進(jìn)程退出后,父進(jìn)程需使用waitpid系統(tǒng)調(diào)用收割子進(jìn)程,防止其稱為僵尸資源
- 在子進(jìn)程中關(guān)閉服務(wù)器套接字后,在父進(jìn)程中也要關(guān)閉服務(wù)器套接字
- 因?yàn)檫M(jìn)程fork后,父子進(jìn)程都有自己的套接字引用指向內(nèi)核的同一份套接字對(duì)象,套接字引用計(jì)數(shù)為2,對(duì)套接字進(jìn)程close,即將套接字對(duì)象的引用計(jì)數(shù)減1
PreForking同步
- 進(jìn)程比線程耗費(fèi)資源,通過(guò)PreForking進(jìn)程池模型對(duì)服務(wù)器開(kāi)辟的進(jìn)程數(shù)量進(jìn)行限制,避免服務(wù)器負(fù)載過(guò)重
- 如果并行的連接數(shù)量超過(guò)了prefork進(jìn)程數(shù)量,后來(lái)的客戶端請(qǐng)求將會(huì)阻塞
單進(jìn)程異步
- 通過(guò)事件輪詢API,查詢相關(guān)套接字是否有響應(yīng)的讀寫(xiě)事件,有則攜帶事件列表返回,沒(méi)有則阻塞
- 拿到讀寫(xiě)事件后,可對(duì)事件相關(guān)的套接字進(jìn)行讀寫(xiě)操作
- 設(shè)置讀寫(xiě)緩沖區(qū)
- Nginx/Nodejs/Redis都是基于異步模型
- 異步模型編碼成本高,易出錯(cuò),通常在公司業(yè)務(wù)代碼中采用同步模型,僅在講究高并發(fā)高性能的場(chǎng)合才使用異步模型
PreForking異步
Tornado/Nginx采用了多進(jìn)程PreForking異步模型,具有良好的高并發(fā)處理能力
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
python關(guān)鍵字and和or用法實(shí)例
這篇文章主要介紹了python關(guān)鍵字and和or用法實(shí)例,本文直接給出實(shí)現(xiàn)代碼,需要的朋友可以參考下2015-05-05簡(jiǎn)單了解python中對(duì)象的取反運(yùn)算符
這篇文章主要介紹了簡(jiǎn)單了解python中對(duì)象的取反運(yùn)算符,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-07-07Python按照某列內(nèi)容對(duì)兩個(gè)DataFrame進(jìn)行合并操作方法
這篇文章主要給大家介紹了關(guān)于Python按照某列內(nèi)容對(duì)兩個(gè)DataFrame進(jìn)行合并操作的相關(guān)資料,文中通過(guò)代碼示例介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Python具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-08-08Python GUI編程學(xué)習(xí)筆記之tkinter界面布局顯示詳解
這篇文章主要介紹了Python GUI編程學(xué)習(xí)筆記之tkinter界面布局顯示,結(jié)合實(shí)例形式分析了Python GUI編程中tkinter界面布局顯示的相關(guān)操作技巧與使用注意事項(xiàng),需要的朋友可以參考下2020-03-03Django 限制用戶訪問(wèn)頻率的中間件的實(shí)現(xiàn)
這篇文章主要介紹了Django 限制用戶訪問(wèn)頻率的中間件的實(shí)現(xiàn),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-08-08Tensorflow訓(xùn)練MNIST手寫(xiě)數(shù)字識(shí)別模型
這篇文章主要為大家詳細(xì)介紹了Tensorflow訓(xùn)練MNIST手寫(xiě)數(shù)字識(shí)別模型,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-02-02