Хорошо, поэтому, основываясь на комментариях, данные вводятся в виде строки, а значения представляют собой списки или словари, а клиент запрашивает объект в виде строки.
К сожалению, не существует безопасного, вменяемого способа прямого доступа к этомусортировка данных перекрестного процесса без некоторого промежуточного этапа сериализации / десериализации.Очевидным выбором, за исключением вопросов безопасности, является pickle
их.msgpack
тоже разумно.
Что касается протокола, если проверенный HTTP слишком медленный для вас, для такого простого цикла запрос-ответ, возможно, просто попросите клиента отправить ключ наполучить, за которым следует нулевой символ или символ новой строки или еще много чего, и сервер напрямую ответит сериализованным объектом, а затем закроет соединение.
Возможно, вы захотите просто сохранить сериализованные данные в базе данных,будь то SQLite или что-то еще.
РЕДАКТИРОВАТЬ: Я решил немного поэкспериментировать.Вот небольшой, довольно наивный asyncio
+ msgpack
сервер + клиент, который делает свое дело:
server.py
import asyncio
import random
import msgpack
import time
from functools import lru_cache
def generate_dict(depth=6, min_keys=1, max_keys=10):
d = {}
for x in range(random.randint(min_keys, max_keys)):
d[x] = (
generate_dict(
depth=depth - 1, min_keys=min_keys, max_keys=max_keys
)
if depth
else "foo" * (x + 1)
)
return d
DATA = {f"{x}": generate_dict() for x in range(10)}
@lru_cache(maxsize=64)
def get_encoded_data(key):
# TODO: this does not clear the cache upon DATA being mutated
return msgpack.packb(DATA.get(key))
async def handle_message(reader, writer):
t0 = time.time()
data = await reader.read(256)
key = data.decode()
addr = writer.get_extra_info("peername")
print(f"Sending key {key!r} to {addr!r}...", end="")
value = get_encoded_data(key)
print(f"{len(value)} bytes...", end="")
writer.write(value)
await writer.drain()
writer.close()
t1 = time.time()
print(f"{t1 - t0} seconds.")
async def main():
server = await asyncio.start_server(handle_message, "127.0.0.1", 8888)
addr = server.sockets[0].getsockname()
print(f"Serving on {addr}")
async with server:
await server.serve_forever()
asyncio.run(main())
client.py
import socket
import msgpack
import time
def get_key(key):
t0 = time.time()
s = socket.socket()
s.connect(("127.0.0.1", 8888))
s.sendall(str(key).encode())
buf = []
while True:
chunk = s.recv(65535)
if not chunk:
break
buf.append(chunk)
val = msgpack.unpackb(b"".join(buf))
t1 = time.time()
print(key, (t1 - t0))
return val
t0 = time.time()
n = 0
for i in range(10):
for x in range(10):
assert get_key(x)
n += 1
t1 = time.time()
print("total", (t1 - t0), "/", n, ":", (t1 - t0) / n)
На моем Mac
- это занимает около 0,02814 секунд на сообщение на принимающей стороне, при пропускной способности одного потребителя 35 запросов в секунду.
- это занимает около 0,00241 секундыза сообщение на стороне обслуживания, для пропускной способности 413 запросов в секунду.
(И как вы можете видеть из того, как генерируется DATA
, полезные нагрузки могут быть довольно большими.)
Надеюсь, это поможет.