2016-05-26 5 views
0

Я бы сделал запрос async к базе данных в функции data_received, но я не знаю, как это сделать. Я написал простой HTTPServer с asyncio.sleep (2), но он не работает.Как исправить выход asyncio из in data_received

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), это работает. Но async не работает.

Что я делаю неправильно?

ответ

2

"Протокол" вы используете из (со ссылкой на документацию):

18.5.4. Транспорты и протоколы (обратный вызов на основе API)

Как явно сказано в документации, это «обратный вызов на основе API», который вызывает обычные методы, и вы не можете изменить, так что упаковка data_received в «@asyncio. coroutine "просто не сработает.

Но есть сопрограммная на основе API, это следующая глава в документации:

18.5.5. Потоки (сопрограммная 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 def и await вместо @asyncio.coroutine и yield from как сделал.