2. Wilson Júnior
Há 3 anos trabalhando como
developer na Globo.com, apaixonado
por tecnologia e pessoas.
Entusiasta com python desde os 14
anos de idade.
Goiano, cerrado roots!
21. Então temos o IOLoop!
● Funciona como um "for" global
● Troca o contexto e retorna quando o IO finalizar
● Simples e fácil uso
● Multi plataforma (select, epoll, poll, kqueue) Windows, Linux e BSD
39. Características
● Escalável, não bloqueante;
● Nasceu na friendfeed; que foi vendida para o Facebook; hoje é mantido
pela comunidade;
● Pode manter milhares de conexões abertas;
● Possui um IO não bloqueante
44. Segundo step: instale o tornado
from tornado.ioloop import IOLoop
from tornado.web import (
Application,
RequestHandler,
)
class HelloWorldHandler(RequestHandler):
def get(self):
self.write("Hello, world")
45. Segundo step: instale o tornado
app = Application([
(r"/", HelloWorldHandler),
])
app.listen(8888)
IOLoop.current().start()
51. Cuidado com execução de tarefas com o uso de CPU alto
class HelloWorldHandler(RequestHandler):
async def get(self):
# processamento de imagens pesadas
# cálculos pesados
# etc.
53. Cuidado com execução de tarefas que façam IO sem usar IOLoop
class HelloWorldHandler(RequestHandler):
async def get(self):
requests.get('https://host.com')
58. Espere mais de uma operação assíncrona
from tornado import gen
class HelloWorldHandler(RequestHandler):
async def get(self):
result01, result02 = await gen.multi([
get_http_result(),
get_http_result(),
])
self.write(json.dumps([result01, result02]))
59. Busque a lib não bloqueante para
o que você vai utilizar.
69. Execute assincronamente via ThreadPoolExecutor
● Vantagens
○ Fica tudo auto-contido dentro de um
app
○ Único processo para manter de pé
● Desvantagens
○ Limitado ao número de threads
○ Processo caiu perdeu jobs
70. Use um ThreadPoolExecutor
import time
from tornado import gen
from tornado.ioloop import IOLoop
from tornado.web import (
Application,
RequestHandler,
)
from tornado.concurrent import run_on_executor
from concurrent.futures import ThreadPoolExecutor
71. Use um ThreadPoolExecutor
class ThreadPoolHandler(RequestHandler):
_thread_pool = ThreadPoolExecutor(10)
@gen.coroutine
def get(self):
result = yield self.sync_job()
self.write(result)
@run_on_executor(executor='_thread_pool')
def sync_job(self):
time.sleep(1)
return 'ok'
72. Use um ThreadPoolExecutor
if __name__ == "__main__":
app = Application([
(r"/", ThreadPoolHandler),
], debug=True)
app.listen(8888)
IOLoop.current().start()
74. Execute assincronamente via barramento (noreply)
● Vantagens
○ Worker pode ser escrito em outra
linguaguem
○ Possibilidade de escalar em muitas
máquinas
○ Bufferização de tasks em uma fila
persistente
● Desvantagens
○ Mais um processo para manter
77. Tutorial: API Restful usando motor +
tornado
● instalaremos o mongo local
● $ pip install motor
78. Tutorial: API Restful usando motor + tornado
import json
import uuid
from tornado.ioloop import IOLoop
from tornado.web import (
Application,
RequestHandler,
)
from motor.motor_tornado import MotorClient
79. Tutorial: API Restful usando motor + tornado
class CollectionNameMixin(object):
@property
def collection_name(self):
raise NotImplementedError
def set_default_headers(self):
self.set_header('content-type', 'application/json')
@property
def collection(self):
return self.application.db[self.collection_name]
80. Tutorial: API Restful usando motor + tornado
class BaseCollectionHandler(
CollectionNameMixin, RequestHandler):
async def get(self):
result = []
async for document in self.collection.find({}):
result.append(document)
self.write(json.dumps(result))
81. Tutorial: API Restful usando motor + tornado
class BaseCollectionHandler(
CollectionNameMixin, RequestHandler):
async def post(self):
body = json.loads(self.request.body)
body['_id'] = str(uuid.uuid4())
await self.collection.insert_one(body)
self.write(json.dumps(body))
82. Tutorial: API Restful usando motor + tornado
class BaseResourceHandler(CollectionNameMixin,
RequestHandler):
async def get(self, resource_id):
where = {"_id": resource_id}
result = await self.collection.find_one(where)
if not result:
self.set_status(404)
self.write('{"error": "Not found"}')
return
self.write(json.dumps(result))
83. Tutorial: API Restful usando motor + tornado
class BaseResourceHandler(CollectionNameMixin,
RequestHandler):
async def put(self, resource_id):
body = json.loads(self.request.body)
result = await self.collection.update_one(
{'_id': resource_id},
{'$set': body}
)
await self.get(resource_id)
84. Tutorial: API Restful usando motor + tornado
class BaseResourceHandler(CollectionNameMixin,
RequestHandler):
async def delete(self, resource_id):
where = {'_id': resource_id}
result = await self.collection.delete_many(where)
if result.deleted_count == 0:
self.set_status(404)
self.write('{"error": "Not found"}')
return
self.set_status(204)
85. Tutorial: API Restful usando motor + tornado
class BaseResourceHandler(CollectionNameMixin,
RequestHandler):
async def delete(self, resource_id):
where = {'_id': resource_id}
result = await self.collection.delete_many(where)
if result.deleted_count == 0:
self.set_status(404)
self.write('{"error": "Not found"}')
return
self.set_status(204)
86. Tutorial: API Restful usando motor + tornado
class PeopleCollectionHandler(BaseCollectionHandler):
collection_name = 'people'
class PeopleResourceHandler(BaseResourceHandler):
collection_name = 'people'
87. Tutorial: API Restful usando motor + tornado
def get_app(db_name='blah'):
app = Application([
(r"/people", PeopleCollectionHandler),
(r"/people/(.*)", PeopleResourceHandler),
])
app.db = MotorClient()[db_name]
return app
if __name__ == "__main__":
get_app().listen(8888)
IOLoop.current().start()