2

我使用Sanic作为服务器并尝试同时处理多个请求。

我已经将 await 用于编码功能(我使用 for 循环来模拟做某事)但是当我time curl http://0.0.0.0:8000/在两个单独的控制台中尝试时,它不会同时运行。

我搜索了谷歌,但只找到 event_loop 但它是安排注册的conroutines。

如何等待 for 循环,以免阻止请求?

谢谢你。

from sanic import Sanic
from sanic import response
from signal import signal, SIGINT
import asyncio
import uvloop

app = Sanic(__name__)


@app.route("/")
async def test(request):
    # await asyncio.sleep(5)
    await encode()
    return response.json({"answer": "42"})

async def encode():
    print('encode')
    for i in range(0, 300000000):
        pass

asyncio.set_event_loop(uvloop.new_event_loop())
server = app.create_server(host="0.0.0.0", port=8000)
loop = asyncio.get_event_loop()
task = asyncio.ensure_future(server)
signal(SIGINT, lambda s, f: loop.stop())
try:
    loop.run_forever()
except:
    loop.stop()
4

2 回答 2

1

由于异步处理程序实际上是在事件循环中运行,因此它作为回调异步运行而不是并发运行。loop.run_forever() 将一遍又一遍地调用 loop._run_once 以运行所有已注册的事件,每次等待都会停止协程并将控制权返回给 eventloop,并且 eventloop 安排运行下一个事件。

所以基本上如果你不想在长时间运行的for循环中阻塞,你需要手动将控制权交还给for循环内的事件循环,请参阅关于放弃控制的问题

async def encode():
    print('encode')
    for i in range(0, 300000000):
        await asyncio.sleep(0)

这是Guido的一句话

asyncio.sleep(0) 的意思就是——让任何其他任务运行,然后回到这里。

于 2018-03-06T05:57:25.330 回答
1

运行for i in range()是阻塞的。如果您更改它以将您await asyncio.sleep(5)的方法放入encode方法中,您将看到它按预期运行。

@app.route("/")
async def test(request):
    await encode()
    return response.json({"answer": "42"})

async def encode():
    print('encode')
    await asyncio.sleep(5)

当您调用await encode()并且 encode 是一种阻塞方法时,它仍然会阻塞,因为您没有“等待”其他任何东西。您的线程仍然被锁定。

您还可以添加另一个工人:

app.create_server(worker=2)

尝试浏览这个答案

于 2018-03-04T11:40:14.290 回答