如何更正 data_received 中的 asyncio yield

How to correct asyncio yield from in data_received

我会在 data_received 函数中向数据库发出异步请求,但我不知道该怎么做。我用 asyncio.sleep(2) 编写了简单的 HTTPServer,但它不起作用。

import time
import asyncio

class HTTPServer:
    def connection_made(self, transport):
        self.transport = transport
        pass

    def connection_lost(self, exc):
        pass

    def eof_received(self):
        pass

    @asyncio.coroutine
    def data_received(self, data):
        try:
            #time.sleep(2)
            yield from asyncio.sleep(2)

            body = "Hello <br/>\n"
            response = 'HTTP/1.1 {status}\r\n'.format(status="200")
            response += 'Content-Length: {size}\r\n'.format(size=len(body))
            response += 'Content-Type: text/html; charset=utf-8\r\n'.format(size=len(body))
            response += 'Connection: close\r\n'.format(size=len(body))
            response += '\r\n'
            response += body
            self.transport.write(response.encode('utf-8'))
        except e:
            print (e)
        self.transport.close()


loop = asyncio.get_event_loop()
print ('Start server on 0.0.0.0:8080')
asyncio.ensure_future(loop.create_server(
    lambda: HTTPServer(),
    '0.0.0.0', 8080
))
try:
    loop.run_forever()
    pass
except KeyboardInterrupt:
    loop.stop()

我注释行 @asyncio.coroutine 并从 asyncio.sleep(2) 中产生,它是有效的。我添加 time.sleep(2) 而不是 asyncio.sleep(2),这是有效的。但是异步不起作用。

我做错了什么?

您正在使用的 "Protocol" 来自(引用文档):

18.5.4. Transports and protocols (callback based API)

正如文档明确指出的那样,它是一个 "callback based API",它调用普通方法,您无法更改它,因此将 data_received 包装在“@asyncio.coroutine”中不行。

但是有一个基于协程的API,这是文档的下一章:

18.5.5. Streams (coroutine based API)

使用基于 API 的协程重写您的示例,您将得到:

import asyncio


async def request_handler(reader, writer):
    await asyncio.sleep(2)
    data = await reader.read(100)
    message = data.decode()
    addr = writer.get_extra_info('peername')
    print("Received %r from %r" % (message, addr))

    body = "Hello <br/>\n"
    response = 'HTTP/1.1 {status}\r\n'.format(status="200")
    response += 'Content-Length: {size}\r\n'.format(size=len(body))
    response += 'Content-Type: text/html; charset=utf-8\r\n'.format(size=len(body))
    response += 'Connection: close\r\n'.format(size=len(body))
    response += '\r\n'
    response += body

    writer.write(response.encode('utf-8'))
    await writer.drain()
    writer.close()

loop = asyncio.get_event_loop()
coro = asyncio.start_server(request_handler, '127.0.0.1', 8080, loop=loop)
server = loop.run_until_complete(coro)

print('Start server on {}'.format(server.sockets[0].getsockname()))
try:
    loop.run_forever()
except KeyboardInterrupt:
    pass

# Close the server
server.close()
loop.run_until_complete(server.wait_closed())
loop.close()

请注意,如果您使用的是 Python 3.5,则可以像我一样使用 async defawait 而不是 @asyncio.coroutineyield from