私はpython3 + asyncioを使って複数プロセスのサーバープログラムを作成しようとしていますが、AbstractEventLoop.create_serverに 'reuse_port'という名前のパラメータがあることがわかりました。python3 asyncio reuse_port経由で正しいマルチプロセスサーバープログラムを書くには?
私はいくつかのコードを書いたので、マルチプロセスを使っていくつかのプロセスを作成し、各プロセスはasyncioイベントループを作成し、これらのプロセスはすべて同じポートでリッスンします。
私はこれらのプロセスが連携してリクエストに応答すると思っていましたが、このサーバープログラムをテストすると、常に1つのプロセスしかリクエストに応答しませんでした。
他のプロセスが要求に応答しないのはなぜですか? 私のコードにバグはありますか?
OSX10.11 + PYTHON3.5.2
サーバー:
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
import os
import sys
import multiprocessing
import asyncio
import socket
tcp_listen_port = 44330
class Listener:
def __init__(self, protocol, listen_port, listen_host='localhost'):
self._protocol = protocol
self._listen_port = listen_port
self._listen_host = listen_host
self._loop = None
self._server = None
self._pid = os.getpid()
def run(self):
asyncio.set_event_loop(asyncio.new_event_loop())
self._loop = asyncio.get_event_loop()
coro = self._loop.create_server(
self._protocol,
host=self._listen_host,
port=self._listen_port,
family=socket.AF_INET,
reuse_port=True
)
self._server = self._loop.run_until_complete(coro)
print('Listener Server on {}, pid {}'.format(
self._server.sockets[0].getsockname(),
self._pid
))
self._loop.run_forever()
def close(self):
self._server.close()
self._loop.run_until_complete(self._server.wait_closed())
self._loop.close()
class ProtocolEcho(asyncio.Protocol):
def connection_made(self, transport):
self.transport = transport
def data_received(self, data):
data = 'hello python asyncio from pid {}\r\n\r\n'.format(os.getpid()).encode()
self.transport.write(data)
self.transport.close()
def create_tcp_srv(listen_port):
listener = Listener(ProtocolEcho, listen_port)
try:
listener.run()
except KeyboardInterrupt:
listener.close()
def main():
cpu_count = multiprocessing.cpu_count()
srvproclist = list()
for i in range(cpu_count):
p = multiprocessing.Process(
target=create_tcp_srv,
args=(tcp_listen_port,)
)
srvproclist.append(p)
for proc in srvproclist:
proc.start()
for proc in srvproclist:
proc.join()
if __name__ == '__main__':
main()
クライアント
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
import os
import asyncio
import multiprocessing
async def req():
connect = asyncio.open_connection('localhost', 44330)
reader, writer = await connect
writer.write('hello'.encode('utf-8'))
await writer.drain()
while True:
line = await reader.readline()
if line == b'\r\n':
break
print('proc {} recv {}'.format(os.getpid(), line.decode()))
writer.close()
def begin_test():
asyncio.set_event_loop(asyncio.new_event_loop())
loop = asyncio.get_event_loop()
tasks = [req() for i in range(10)]
loop.run_until_complete(asyncio.wait(tasks))
loop.close()
plist = list()
for i in range(4):
p = multiprocessing.Process(
target=begin_test
)
plist.append(p)
for proc in plist:
proc.start()
for proc in plist:
proc.join()
このようなクライアント出力:
proc 72319 recv hello python asyncio from pid 72310
proc 72318 recv hello python asyncio from pid 72310
proc 72319 recv hello python asyncio from pid 72310
proc 72320 recv hello python asyncio from pid 72310
proc 72321 recv hello python asyncio from pid 72310
proc 72319 recv hello python asyncio from pid 72310
proc 72318 recv hello python asyncio from pid 72310
proc 72320 recv hello python asyncio from pid 72310
proc 72321 recv hello python asyncio from pid 72310
proc 72318 recv hello python asyncio from pid 72310
proc 72320 recv hello python asyncio from pid 72310
proc 72321 recv hello python asyncio from pid 72310
最後の数字「72310」は私の要求に応えるサーバープロセスのPIDです。そのため、プロセスが1つしかないと思っていました。しかし、なぜ...