1

我正在尝试制作一个 HTTP API,它可以创建和销毁打开 TCP 连接到远程服务器流式传输约 15 秒数据的并发任务。稍后我将不得不弄清楚如何处理数据。现在我只是打印它。

在下面的示例中,我可以通过导航到http://192.168.1.1:5000/addconnection来创建多个 TCP 连接。

问题:

1)这种方法合理吗?我认为 Flask 可能会为每个 /addconnection 请求创建一个新线程。我不确定这样做会遇到什么性能限制。

2)是否可以跟踪每个连接?我想实现/listconnections 和/removeconnections。

3)有没有更Pythonic的方式来做到这一点?我读过一些关于 Celery 的文章,但我还不是很了解它。也许还有其他已经存在的工具可以处理类似的问题。

import trio
from flask import Flask
app = Flask(__name__)

@app.route("/")
def hello():
    return "Hello World!"


@app.route("/addconnection")
def addconnection():

    async def receiver(client_stream):
        print("Receiver: started!")
        while True:
            data = await client_stream.receive_some(16800)
            print("Received Data: {}".format(data))

    async def parent():
        async with trio.open_nursery() as nursery:
            client_stream = await trio.open_tcp_stream('192.168.1.1', 1234)
            nursery.start_soon(receiver, client_stream)

    trio.run(parent)

4

2 回答 2

2

1)您将为每个 /addconnection 请求创建一个新的事件循环,这将阻塞 Flask 运行时。这可能会将您限制为每个线程的单个请求。

2)是的,在最简单的情况下,您可以将它们存储在全局集中,见connections下文。

3)我是Quart-Trio的作者,我认为这是一种更好的方式。Quart 是用 async/await 重新实现的 Flask API(解决了 1 中的大部分问题)。Quart-Trio 是使用 Trio 而不是 Quart 的 asyncio 的扩展。

大致(我还没有测试过)你的代码变成了,

import trio
from quart_trio import QuartTrio

connections = set()

app = QuartTrio(__name__)

@app.route("/")
async def hello():
    return "Hello World!"


@app.route("/addconnection")
async def addconnection():

    async def receiver(client_stream):
        print("Receiver: started!")
        while True:
            data = await client_stream.receive_some(16800)
            print("Received Data: {}".format(data))

    async def parent():
        async with trio.open_nursery() as nursery:
            client_stream = await trio.open_tcp_stream('192.168.1.1', 1234)
            connections.add(client_stream)
            nursery.start_soon(receiver, client_stream)
        connections.remove(client_stream)

    app.nursery.start_soon(parent)
    return "Connection Created"

if __name__ == "__main__":
    # Allows this to run and serve via python script.py
    # For production use `hypercorn -k trio script:app`
    app.run()
于 2019-03-08T19:52:45.083 回答
-1

在你有的地方,async def receiver(client_stream):我会在每次循环迭代之间放置一个等待await trio.sleep(0.029),以便让程序的其余部分有机会运行。您可以根据您希望该功能的繁忙程度增加睡眠时间。但是,如果您执行该循环,您的应用程序可能会冻结。还应该使用取消块,这样您就不会永远被困在读取数据中。

于 2021-12-04T11:09:04.463 回答