gpt4 book ai didi

python - asyncio 与同步代码

转载 作者:行者123 更新时间:2023-12-04 02:58:08 25 4
gpt4 key购买 nike

我有一个模块可以阻止对某些 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)。可能吗?

附言我希望它像这样使用:

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())

最佳答案

HelloService 可能需要使用 run_in_executor(管理线程池)​​在后台运行 HelloNetClient 方法。例如:

async def say_hello(self):
print('Saying hello...')
loop = asyncio.get_event_loop()
return await loop.run_in_executor(None, self.hello_client.say_hello_net)

这不是 asyncio 的惯用用法,您会错过它的一些功能 - 例如,您将无法创建数千个并行工作的客户端,并且您将无法获得可靠的取消(cancel() 任何你想要的任务的能力)。尽管如此,简单的使用就可以正常工作。

不幸的是,提供自定义传输的能力在这里没有帮助,因为中间层 HelloNetClient 需要同步行为。即使您要编写一个连接到 asyncio 的自定义传输,像 say_hello_net 这样的方法仍然会等待响应到达所需的时间,因此 HelloService 会将它们安排在一个单独的线程中。出于这个原因,您最好的选择是使用默认传输并将带有 asyncio 的代码与服务中的代码连接起来,如上所示。

关于python - asyncio 与同步代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51919188/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com