如何在data_received中更正asyncio yield

时间:2016-05-26 05:08:11

标签: python python-3.x python-3.5 httpserver python-asyncio

我会在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),它的工作原理。但异步不起作用。

我做错了什么?

1 个答案:

答案 0 :(得分:2)

您使用的“协议”来自(引用文档):

  

18.5.4。传输和协议(基于回调的API)

正如文档中明确指出的那样,它是一个“基于回调的API”,它调用普通方法,你无法改变它,因此将data_received包装在“@ asyncio.coroutine”中是行不通的

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

  

18.5.5。 Streams(基于协程的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