Python3 asyncio - 运行 两个服务器在自己的线程中
Python3 asyncio - running two servers in own thread
我的服务器 类 继承自 BaseServer
:
class BaseServer(object):
def __init__(self, host, port):
self.loop = asyncio.new_event_loop()
asyncio.set_event_loop(self.loop)
self.instance = asyncio.start_server(self.handle_connection, host = host, port = port)
async def handle_connection(self, reader: StreamReader, writer: StreamWriter):
pass
def start(self):
# wrapping coroutine into ensure_future to allow it to call from call_soon
# wrapping into lambda to make it callable
callback = asyncio.ensure_future(self.instance)
self.loop.call_soon(lambda: callback)
self.loop.run_forever()
self.loop.close()
def stop(self):
self.loop.call_soon_threadsafe(self.loop.stop)
@staticmethod
def get_instance():
return BaseServer(None, None)
我需要两个服务器 运行在自己的线程中并行处理请求。
但是当我根据需要尝试 运行 它们时,只有第一台服务器是 运行ning。下面我如何 运行 他们:
if __name__ == '__main__':
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
async def run():
pool = ThreadPoolExecutor(max_workers=cpu_count())
await loop.run_in_executor(pool, Server1.get_instance().start)
await loop.run_in_executor(pool, Server2.get_instance().start)
loop.run_until_complete(run())
- 我做错了什么?如何 运行 每个服务器在自己的线程中?
- 当
asyncio.set_event_loop
从 def __init__
调用时,我收到下一个错误:
RuntimeError: There is no current event loop in thread 'Thread-1'.
但是,如果我从 def __init__
中删除 asyncio.set_event_loop
并将其移至 def start
,错误就会消失。为什么会这样?
跟进 OP 的评论:
But running two servers via run_until_complete in the same loop blocks loop for one of servers to process request to another, isn't it ? How to run two servers correctly ?
这是 python 3.5 的 asyncio 文档中 TCP server example 的修改版本:
# Start server 1
coro1 = asyncio.start_server(handle_echo, '127.0.0.1', 8888, loop=loop)
server1 = loop.run_until_complete(coro1)
print('Serving 1 on {}'.format(server1.sockets[0].getsockname()))
# Start server 2
coro2 = asyncio.start_server(handle_echo, '127.0.0.1', 8889, loop=loop)
server2 = loop.run_until_complete(coro2)
print('Serving 2 on {}'.format(server2.sockets[0].getsockname()))
# Serve requests until Ctrl+C is pressed
try:
loop.run_forever()
except KeyboardInterrupt:
pass
# Close the servers
server1.close()
loop.run_until_complete(server1.wait_closed())
server2.close()
loop.run_until_complete(server2.wait_closed())
# Close the loop
loop.close()
请注意,随着 python 3.7 添加到 asyncio,它看起来 much nicer:
async def main():
server1 = await asyncio.start_server(
handle_echo, '127.0.0.1', 8888)
addr1 = server1.sockets[0].getsockname()
print(f'Serving 1 on {addr1}')
server2 = await asyncio.start_server(
handle_echo, '127.0.0.1', 8889)
addr2 = server2.sockets[0].getsockname()
print(f'Serving 2 on {addr2}')
async with server1, server2:
await asyncio.gather(
server1.serve_forever(), server2.serve_forever())
asyncio.run(main())
我的服务器 类 继承自 BaseServer
:
class BaseServer(object):
def __init__(self, host, port):
self.loop = asyncio.new_event_loop()
asyncio.set_event_loop(self.loop)
self.instance = asyncio.start_server(self.handle_connection, host = host, port = port)
async def handle_connection(self, reader: StreamReader, writer: StreamWriter):
pass
def start(self):
# wrapping coroutine into ensure_future to allow it to call from call_soon
# wrapping into lambda to make it callable
callback = asyncio.ensure_future(self.instance)
self.loop.call_soon(lambda: callback)
self.loop.run_forever()
self.loop.close()
def stop(self):
self.loop.call_soon_threadsafe(self.loop.stop)
@staticmethod
def get_instance():
return BaseServer(None, None)
我需要两个服务器 运行在自己的线程中并行处理请求。 但是当我根据需要尝试 运行 它们时,只有第一台服务器是 运行ning。下面我如何 运行 他们:
if __name__ == '__main__':
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
async def run():
pool = ThreadPoolExecutor(max_workers=cpu_count())
await loop.run_in_executor(pool, Server1.get_instance().start)
await loop.run_in_executor(pool, Server2.get_instance().start)
loop.run_until_complete(run())
- 我做错了什么?如何 运行 每个服务器在自己的线程中?
- 当
asyncio.set_event_loop
从def __init__
调用时,我收到下一个错误:
RuntimeError: There is no current event loop in thread 'Thread-1'.
但是,如果我从 def __init__
中删除 asyncio.set_event_loop
并将其移至 def start
,错误就会消失。为什么会这样?
跟进 OP 的评论:
But running two servers via run_until_complete in the same loop blocks loop for one of servers to process request to another, isn't it ? How to run two servers correctly ?
这是 python 3.5 的 asyncio 文档中 TCP server example 的修改版本:
# Start server 1
coro1 = asyncio.start_server(handle_echo, '127.0.0.1', 8888, loop=loop)
server1 = loop.run_until_complete(coro1)
print('Serving 1 on {}'.format(server1.sockets[0].getsockname()))
# Start server 2
coro2 = asyncio.start_server(handle_echo, '127.0.0.1', 8889, loop=loop)
server2 = loop.run_until_complete(coro2)
print('Serving 2 on {}'.format(server2.sockets[0].getsockname()))
# Serve requests until Ctrl+C is pressed
try:
loop.run_forever()
except KeyboardInterrupt:
pass
# Close the servers
server1.close()
loop.run_until_complete(server1.wait_closed())
server2.close()
loop.run_until_complete(server2.wait_closed())
# Close the loop
loop.close()
请注意,随着 python 3.7 添加到 asyncio,它看起来 much nicer:
async def main():
server1 = await asyncio.start_server(
handle_echo, '127.0.0.1', 8888)
addr1 = server1.sockets[0].getsockname()
print(f'Serving 1 on {addr1}')
server2 = await asyncio.start_server(
handle_echo, '127.0.0.1', 8889)
addr2 = server2.sockets[0].getsockname()
print(f'Serving 2 on {addr2}')
async with server1, server2:
await asyncio.gather(
server1.serve_forever(), server2.serve_forever())
asyncio.run(main())