ZeroMQ (0MQ) [官方文檔]是一個漂亮的庫,它用一個非常輕便的基於模式的包裝器,替換socket層。
另外,0MQ通常還保證一次讀取將返回一條消息(或多部分消息的一部分)。
gevent是一個基於協程的第三方網絡庫,它允許你當發生IO阻塞時(如網絡請求)去執行其他的操作,當你並行執行很多IO耗時的操作時能達到非常好的併發效果。
gevent是一種折衷方案,可以以同步的操作效率提高到與多線程相當的程度,典型的應用場景就是請求網絡的操作。
曾經有一段時間ZeroMQ不支持這一點(必須使用一個名爲gevent zmq的包),但後來zmq與gevent兼容了。最新的版本18.1.0是支持的。
爲了實現協程併發效果,需要引用import zmq.green
而不是 import zmq
。
服務端示例代碼:
import gevent
import time
import zmq.green as zmq
_BINDING = 'tcp://127.0.0.1:7000'
context = zmq.Context()
def server():
server_socket = context.socket(zmq.REP)
server_socket.bind(_BINDING)
while True:
received = server_socket.recv()
print("Received: [{}]\n".format(received))
server_socket.send_string('TestResponse')
server = gevent.spawn(server)
server.join()
對應的客戶端
import gevent
import time
import zmq.green as zmq
_BINDING = 'tcp://127.0.0.1:7000'
context = zmq.Context()
def client():
client_socket = context.socket(zmq.REQ)
client_socket.connect(_BINDING)
client_socket.send_string("TestMessage")
response = client_socket.recv()
print("Response: [{}] at {}".format(response, time.time()))
server = gevent.spawn(server)
clients = [gevent.spawn(client) for i in range(1000)]
分別啓動服務端和客戶端,服務端輸出:
Received: [b'TestMessage']
Received: [b'TestMessage']
Received: [b'TestMessage']
.....
客戶端輸出:
Response: [b'TestResponse'] at 1565866988.859491
Response: [b'TestResponse'] at 1565866988.859531
Response: [b'TestResponse'] at 1565866988.859568
Response: [b'TestResponse'] at 1565866988.859606
Response: [b'TestResponse'] at 1565866988.859644
Response: [b'TestResponse'] at 1565866988.859683
Response: [b'TestResponse'] at 1565866988.859721
Response: [b'TestResponse'] at 1565866988.860918
Response: [b'TestResponse'] at 1565866988.8609679
Response: [b'TestResponse'] at 1565866988.861006
......