我有一个模块,该模块可以阻止对某些TCP服务器的网络请求并接收响应。我必须将其集成到asyncio应用程序中。我的模块如下所示:
import socket
# class providing transport facilities
# can be implemented in any manner
# for example it can manage asyncio connection
class CustomTransport:
def __init__(self, host, port):
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.host = host
self.port = port
def write(self, data):
left = len(data)
while left:
written = self.sock.send(data.encode('utf-8'))
left = left - written
data = data[written:]
def read(self, sz):
return self.sock.recv(sz)
def open(self):
self.sock.connect((self.host, self.port))
def close(self):
self.sock.shutdown(2)
# generated. shouldn't be modified
# however any transport can be passed
class HelloNetClient:
def __init__(self, transport):
self.transport = transport
def say_hello_net(self):
self.transport.write('hello')
response = self.transport.read(5)
return response
# can be modified
class HelloService:
def __init__(self):
# create transport for connection to echo TCP server
self.transport = CustomTransport('127.0.0.1', 6789)
self.hello_client = HelloNetClient(self.transport)
def say_hello(self):
print('Saying hello...')
return self.hello_client.say_hello_net()
def __enter__(self):
self.transport.open()
return self
def __exit__(self,exc_type, exc_val, exc_tb):
self.transport.close()
用法:
def start_conversation():
with HelloService() as hs:
answer = hs.say_hello()
print(answer.decode('utf-8'))
if __name__ == "__main__":
start_conversation()
现在,我看到使模块与 asyncio 兼容的唯一方法是将所有内容转换为协程,并用asyncio提供的传输替换常规套接字。但是我不想触摸生成的代码(HelloNetClient)。有可能吗?
P.S。我希望这样使用它:
async def start_conversation():
async with HelloService() as hs:
answer = await hs.say_hello()
print(answer.decode('utf-8'))
if __name__ == "__main__":
loop = asyncio.get_event_loop()
loop.run_until_complete(start_conversation())
答案 0 :(得分:0)
HelloService
可能需要使用run_in_executor
(管理线程池)在后台运行HelloNetClient
方法。例如:
async def say_hello(self):
print('Saying hello...')
loop = asyncio.get_event_loop()
return await loop.run_in_executor(self.hello_client.say_hello_net)
这不是asyncio的惯用用法,并且您缺少其某些功能-例如,您将无法创建成千上万个并行工作的客户端,并且您将无法获得可靠的取消(能够cancel()
完成您想要的任何任务)。尽管如此,简单的用法也可以。
不幸的是,此处提供自定义传输的功能没有帮助,因为中间层HelloNetClient
期望同步行为。即使您要编写一个挂接到asyncio的自定义传输,say_hello_net
之类的方法仍会等待,直到它需要响应才能到达,因此HelloService
必须将它们安排在单独的时间中线。因此,最好的选择是使用默认传输方式,并将带有asyncio的代码与服务中的代码连接起来。