感谢之前回答的人,现在我可以构建一个多进程 TCP 服务器,每个进程分别运行一个异步服务器,但全部绑定到一个端口。
(使用 asyncio 时无法使用 os.fork() 将多个进程绑定到一个套接字服务器 https://stackoverflow.com/questions/56409531/could-not-use-os-fork-bind-several-process-to-one-socket-server-when-using-asy)
理论上?当每个进程平等地处理传入消息时,该模型将实现最佳性能。好处可能是更低的延迟或更高的 tps?我不知道。
问题就在这里。我创建了一个四进程服务器,并统计了每个进程接受多少个tcp请求(通过一段时间循环的客户端不断发出新的连接请求)。结果就像{p1:20000次,p2:16000次,p3:13000次次,p4:10000次}
我正在弄清楚锁是否会有所帮助(让获得锁的进程接受请求,而不是让进程直接竞争性地接受请求)。但事实证明,只有父进程才能获得锁,而其他进程可以获得锁根本不能。
试图找出解决方案,需要您的帮助。
这是一个简单的示例服务器代码(预分叉模型,其中进程竞争性地直接接受请求):
# sample_server.py
import asyncio
import os
from socket import *
def create_server():
sock = socket(AF_INET , SOCK_STREAM)
sock.setsockopt(SOL_SOCKET , SO_REUSEADDR ,1)
sock.bind(('',25000))
sock.listen()
sock.setblocking(False)
return sock
async def start_serving(loop , server):
while True:
client ,addr = await loop.sock_accept(server)
loop.create_task(loop ,client)
async def handler(loop ,client):
with client:
while True:
data = await loop.sock_recv(client , 64)
if not data: break
print(f"Incoming message {data} at pid {pid}")
await loop.sock_sendall(client , data)
server = create_server()
for i in range(4 - 1):
pid = os.fork()
if pid <= 0:
break
pid = os.getpid()
loop = asyncio.get_event_loop()
loop.create_task(start_serving(loop , server))
loop.run_forever()
然后我们可以将其输出重定向到这样的文件中:
python3 sample_server.py > sample_server.output
下一步也许我们粗略地处理这些数据:
import re
from collections import Counter
with open('./sample_server.output','r') as f:
cont = file.read()
pat = re.compile('[\d]{4}')
res = pat.findall(cont)
print(Counter(res))
获取如下输出(其中 key 表示端口号,而 value 表示它们处理的回声数量):
Counter({'3788': 23136, '3789': 18866, '3791': 18263, '3790': 10817})
不等式。
当我像这样引入多处理锁时,事情变得更糟:
from multiprocessing import Lock
l = Lock()
async def start_serving(loop , server):
while True:
with l:
client ,addr = await loop.sock_accept(server)
loop.create_task(loop ,client)
^ 那么唯一可以接受请求的进程就是父进程。而子进程被完全阻止。似乎如果您在进程被阻止之前获取了锁,那么它总是会表现得像这样。解释器只是忠实地执行我们告诉它的操作。
总之,这是我的两个问题:
- 1\是否有任何方法让这个预分叉的异步服务器负载平衡?
- 2\ 有没有办法引入锁来帮助解决这个问题?
Thanks!
PS:谁能告诉我如何在pypy的解释器中使用uvloop驱动eventloop?十分感谢!