SlideShare una empresa de Scribd logo
1 de 97
Descargar para leer sin conexión
Escreva aplicações web
assíncronas com Python3 +
Tornado
Wilson Júnior
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!
Entendendo as bases do
asyncronismo
Uma aplicação pode ser dividida
em 2 tempos
CPU Bound
CPU Bound
Tempo que sua aplicação está voltada
apenas para o uso do processador ...
CPU Bound
CPU Bound (exemplos)
● Cálculos matemáticos pesados
● Conversão de imagens
● Encoding de vídeo
IO Bound
IO Bound
Tempo que sua aplicação está voltada
apenas para comunicação com
interfaces de saída como:
IO Bound
● Comunicação com serviços
externos (banco de dados, HTTP,
redis, etc)
● Comunicação com dispositivos
locais (HD, Fita, DVD, pendrive, etc)
O que acontece quando fazemos
uma chamada que faz IO no
python
Exemplo de aplicação IO Bound
import requests
url = 'https://www.google.com.br'
response = requests.get(url, timeout=10)
Se este request HTTP demorar 10
segundos, o que acontece com a
aplicação ?
IOWait!!
O que vem acontecendo nos
últimos anos com nossas
aplicações ...
O número de clientes das
aplicações mudou!
O número de clientes das aplicações mudou!
Otimizar o tempo de IO para
alcançarmos maior número de
clientes.
Então temos o IOLoop!
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
O que um ioloop trouxe de
melhoria
As aplicações não ficam travadas
em IOWait!
Aviso sobre o conceito!
Não bloqueie o IOLoop com
operações que querem alto cpu
bound!
Features do python 3.6
Async functions!
Aprenda a separar IO bound de
CPU bound
Podemos fazer o seguinte
approach!
Funções que fazem IO são async!
Funções que não fazem IO são
tradicionais
Funções que fazem IO
async def async_func():
# do something async
E como pego o retorno de uma
função assíncrona ?!
await nela!
Funções que fazem IO
async def async_func():
# do something async
async def blah():
ret = await async_func()
Funções que fazem IO
async def async_func():
# do something async
async def blah():
ret = await async_func()
Só posso fazer await dentro de
outra função assíncrona!
Tornado web framework!
tornadoweb.org
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
Vamos começar um projetinho
em tornado ?!
Primeiro step: crie um virtualenv
com python 3.6
Primeiro step: crie um virtualenv com python 3.6
$ which python3.6
/usr/local/bin/python3.6
$ mkvirtualenv myproject -p /usr/local/bin/python3.6
Segundo step: instale o tornado
$ pip install tornado
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")
Segundo step: instale o tornado
app = Application([
(r"/", HelloWorldHandler),
])
app.listen(8888)
IOLoop.current().start()
Fazendo requests utilizando
tornado
Novos imports
import json
from tornado.ioloop import IOLoop
from tornado.web import (
Application,
RequestHandler,
)
from tornado.httpclient import AsyncHTTPClient
Realizando requests
async def get_http_result():
url = (
'https://raw.githubusercontent.com'
'/backstage/functions/master/package.json'
)
response = await AsyncHTTPClient().fetch(url,
validate_cert=False)
data = json.loads(response.body)
return {
'heey': data['name'],
}
Realizando requests
class HelloWorldHandler(RequestHandler):
async def get(self):
result = await get_http_result()
self.write(json.dumps(result))
Cuidado com execução de
tarefas com o uso de CPU alto
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.
Cuidado com execução de
tarefas que façam IO sem usar
IOLoop
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')
Teste assíncronamente!
Teste assincronadamente
import unittest
from tornado.testing import AsyncTestCase, gen_test
from blah import get_http_result
class MyTest(AsyncTestCase):
@gen_test
async def test_ok(self):
result = await get_http_result()
self.assertEqual(result, {'heey': 'backstage-functions'})
Teste assincronadamente
$ pip install nose
$ nosetests test.py
Espere mais de uma operação
assíncrona
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]))
Busque a lib não bloqueante para
o que você vai utilizar.
Banco de Dados
MySQL:
github.com/PyMySQL/Tornado-M
ySQL
MongoDB: motor.readthedocs.io
Redis:
github.com/aio-libs/aioredis
Brokers
Stomp:
github.com/wpjunior/torstomp
AMQP: pika.readthedocs.io
Alternativas para tarefas CPU
intensive
Use um ThreadPoolExecutor
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
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
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'
Use um ThreadPoolExecutor
if __name__ == "__main__":
app = Application([
(r"/", ThreadPoolHandler),
], debug=True)
app.listen(8888)
IOLoop.current().start()
Execute assincronamente via
barramento (noreply)
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
Execute assincronamente via barramento (noreply)
Tutorial: API Restful usando
motor + tornado
Tutorial: API Restful usando motor +
tornado
● instalaremos o mongo local
● $ pip install motor
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
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]
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))
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))
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))
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)
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)
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)
Tutorial: API Restful usando motor + tornado
class PeopleCollectionHandler(BaseCollectionHandler):
collection_name = 'people'
class PeopleResourceHandler(BaseResourceHandler):
collection_name = 'people'
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()
Vamos testar nossa aplicação ?!
Vamos testar nossa aplicação ?!
import json
from tornado.testing import AsyncHTTPTestCase, gen_test
from rest_mongo import get_app
Vamos testar nossa aplicação ?!
class MyTest(AsyncHTTPTestCase):
def get_app(self):
return get_app('test-database')
def setUp(self):
super().setUp()
def drop_collection_result(*args):
self.stop()
self.get_app().db.drop_collection(
'people', callback=drop_collection_result)
self.wait()
Vamos testar nossa aplicação ?!
class MyTest(AsyncHTTPTestCase):
def test_not_found(self):
response = self.fetch('/people/1234')
self.assertEqual(response.code, 404)
self.assertEqual(response.headers['content-type'],
'application/json')
body = json.loads(response.body)
self.assertEqual(body, {'error': 'Not found'})
Vamos testar nossa aplicação ?!
class MyTest(AsyncHTTPTestCase):
def test_create_and_get(self):
# create
response = self.fetch('/people', method='POST',
body='{"name": "created"}')
self.assertEqual(response.code, 201)
self.assertEqual(response.headers['content-type'],
'application/json')
body = json.loads(response.body)
self.assertEqual(body['name'], 'created')
Vamos testar nossa aplicação ?!
class MyTest(AsyncHTTPTestCase):
def test_create_and_get(self):
...
# get
response = self.fetch('/people/%s' % body["_id"])
self.assertEqual(response.code, 200)
self.assertEqual(response.headers['content-type'],
'application/json')
body = json.loads(response.body)
self.assertEqual(body['name'], 'created')
Vamos testar então !?
Tutorial resolvido
github.com/wpjunior/python36-a
sync
Obrigado
github.com/wpjunior about.me/wpjunior
Temos projetos em tornado, venha trabalhar
na Globo.com
talentos.globo.com
Projetos

Más contenido relacionado

La actualidad más candente

JavaScript - De verdade
JavaScript - De verdadeJavaScript - De verdade
JavaScript - De verdadeLuis Vendrame
 
Técnicas para preparação e desenvolvimento de sites em django
Técnicas para preparação e desenvolvimento de sites em djangoTécnicas para preparação e desenvolvimento de sites em django
Técnicas para preparação e desenvolvimento de sites em djangoMario Chaves
 
TDD - Test Driven Development (em PHP)
TDD - Test Driven Development (em PHP)TDD - Test Driven Development (em PHP)
TDD - Test Driven Development (em PHP)Augusto Pascutti
 
Spock Framework
Spock FrameworkSpock Framework
Spock FrameworkIsmael
 
Implementação de Aplicações Móveis e Jogos com Python - Aula 5
Implementação de Aplicações Móveis e Jogos com Python - Aula 5Implementação de Aplicações Móveis e Jogos com Python - Aula 5
Implementação de Aplicações Móveis e Jogos com Python - Aula 5Flávio Ribeiro
 
Tutorial dev cpp 002 - criação, leitura e alteração de arquivos
Tutorial dev cpp   002 - criação, leitura e alteração de arquivosTutorial dev cpp   002 - criação, leitura e alteração de arquivos
Tutorial dev cpp 002 - criação, leitura e alteração de arquivosFlávio Freitas
 
Spock Framework 2
Spock Framework 2Spock Framework 2
Spock Framework 2Ismael
 
Theano - Alto Desempenho em Machine Learning
Theano - Alto Desempenho em Machine LearningTheano - Alto Desempenho em Machine Learning
Theano - Alto Desempenho em Machine LearningFelipe Martins
 
Implementação de Aplicações Móveis e Jogos com Python - Aula 4
Implementação de Aplicações Móveis e Jogos com Python - Aula 4Implementação de Aplicações Móveis e Jogos com Python - Aula 4
Implementação de Aplicações Móveis e Jogos com Python - Aula 4Flávio Ribeiro
 
Gerando bindings de bibliotecas C++ para Python
Gerando bindings de bibliotecas C++ para PythonGerando bindings de bibliotecas C++ para Python
Gerando bindings de bibliotecas C++ para PythonMarcelo Lira
 
Implementação de Aplicações Móveis e Jogos com Python - Aula 3
Implementação de Aplicações Móveis e Jogos com Python - Aula 3Implementação de Aplicações Móveis e Jogos com Python - Aula 3
Implementação de Aplicações Móveis e Jogos com Python - Aula 3Flávio Ribeiro
 

La actualidad más candente (20)

Doctrine for Dummies
Doctrine for DummiesDoctrine for Dummies
Doctrine for Dummies
 
JavaScript - De verdade
JavaScript - De verdadeJavaScript - De verdade
JavaScript - De verdade
 
Técnicas para preparação e desenvolvimento de sites em django
Técnicas para preparação e desenvolvimento de sites em djangoTécnicas para preparação e desenvolvimento de sites em django
Técnicas para preparação e desenvolvimento de sites em django
 
TDD - Test Driven Development (em PHP)
TDD - Test Driven Development (em PHP)TDD - Test Driven Development (em PHP)
TDD - Test Driven Development (em PHP)
 
Spock Framework
Spock FrameworkSpock Framework
Spock Framework
 
Implementação de Aplicações Móveis e Jogos com Python - Aula 5
Implementação de Aplicações Móveis e Jogos com Python - Aula 5Implementação de Aplicações Móveis e Jogos com Python - Aula 5
Implementação de Aplicações Móveis e Jogos com Python - Aula 5
 
Dependency injection
Dependency injectionDependency injection
Dependency injection
 
Tutorial dev cpp 002 - criação, leitura e alteração de arquivos
Tutorial dev cpp   002 - criação, leitura e alteração de arquivosTutorial dev cpp   002 - criação, leitura e alteração de arquivos
Tutorial dev cpp 002 - criação, leitura e alteração de arquivos
 
Spock Framework 2
Spock Framework 2Spock Framework 2
Spock Framework 2
 
Theano - Alto Desempenho em Machine Learning
Theano - Alto Desempenho em Machine LearningTheano - Alto Desempenho em Machine Learning
Theano - Alto Desempenho em Machine Learning
 
Floggy-JustJava-2008-09-10
Floggy-JustJava-2008-09-10Floggy-JustJava-2008-09-10
Floggy-JustJava-2008-09-10
 
Implementação de Aplicações Móveis e Jogos com Python - Aula 4
Implementação de Aplicações Móveis e Jogos com Python - Aula 4Implementação de Aplicações Móveis e Jogos com Python - Aula 4
Implementação de Aplicações Móveis e Jogos com Python - Aula 4
 
Python 03
Python 03Python 03
Python 03
 
Gerando bindings de bibliotecas C++ para Python
Gerando bindings de bibliotecas C++ para PythonGerando bindings de bibliotecas C++ para Python
Gerando bindings de bibliotecas C++ para Python
 
Floggy-GUJavaSC-2008-09-20
Floggy-GUJavaSC-2008-09-20Floggy-GUJavaSC-2008-09-20
Floggy-GUJavaSC-2008-09-20
 
Javascript avançado
Javascript avançadoJavascript avançado
Javascript avançado
 
OOP ObjC
OOP ObjCOOP ObjC
OOP ObjC
 
Al sweigart, cap 3
Al sweigart, cap 3Al sweigart, cap 3
Al sweigart, cap 3
 
Implementação de Aplicações Móveis e Jogos com Python - Aula 3
Implementação de Aplicações Móveis e Jogos com Python - Aula 3Implementação de Aplicações Móveis e Jogos com Python - Aula 3
Implementação de Aplicações Móveis e Jogos com Python - Aula 3
 
Pilhas java
Pilhas javaPilhas java
Pilhas java
 

Similar a Escreva aplicações web assíncronas com python3 + tornado

PyData - Consumindo e publicando web APIs com Python
PyData - Consumindo e publicando web APIs com PythonPyData - Consumindo e publicando web APIs com Python
PyData - Consumindo e publicando web APIs com PythonBruno Rocha
 
Ionic Framework - Parte 1 - Iniciando um Projeto mais Robusto
Ionic Framework - Parte 1 - Iniciando um Projeto mais RobustoIonic Framework - Parte 1 - Iniciando um Projeto mais Robusto
Ionic Framework - Parte 1 - Iniciando um Projeto mais RobustoAlamo Saravali
 
Aprendendo Na Prática: Aplicativos Web com HTML5, Angular.js, Twitter Bootstr...
Aprendendo Na Prática: Aplicativos Web com HTML5, Angular.js, Twitter Bootstr...Aprendendo Na Prática: Aplicativos Web com HTML5, Angular.js, Twitter Bootstr...
Aprendendo Na Prática: Aplicativos Web com HTML5, Angular.js, Twitter Bootstr...Daniel Makiyama
 
Ionic Framework - Configuração do ambiente e a criação da primeira APP
Ionic Framework - Configuração do ambiente e a criação da primeira APPIonic Framework - Configuração do ambiente e a criação da primeira APP
Ionic Framework - Configuração do ambiente e a criação da primeira APPFabio Godoy
 
Otimização de Aplicações Android
Otimização de Aplicações AndroidOtimização de Aplicações Android
Otimização de Aplicações AndroidPeslPinguim
 
Desenvolvimento Agil Com Doctrine Orm
Desenvolvimento Agil Com Doctrine OrmDesenvolvimento Agil Com Doctrine Orm
Desenvolvimento Agil Com Doctrine OrmGuilherme Blanco
 
Apresentacao android por Júlio Cesar Bueno Cotta
Apresentacao android por Júlio Cesar Bueno CottaApresentacao android por Júlio Cesar Bueno Cotta
Apresentacao android por Júlio Cesar Bueno CottaGPrimola
 
Como ser programador durante o dia e mesmo assim dormir bem à noite
Como ser programador durante o dia e mesmo assim dormir bem à noiteComo ser programador durante o dia e mesmo assim dormir bem à noite
Como ser programador durante o dia e mesmo assim dormir bem à noiteComunidade NetPonto
 
Desenvolvimento de Aplicações para o Google App Engine (CPBR5)
Desenvolvimento de Aplicações para o Google App Engine (CPBR5)Desenvolvimento de Aplicações para o Google App Engine (CPBR5)
Desenvolvimento de Aplicações para o Google App Engine (CPBR5)Carlos Duarte do Nascimento
 
Desenvolvimento de aplicações para o Google App Engine
Desenvolvimento de aplicações para o Google App EngineDesenvolvimento de aplicações para o Google App Engine
Desenvolvimento de aplicações para o Google App EngineCampus Party Brasil
 
Integração de sistemas legados com Plone
Integração de sistemas legados com PloneIntegração de sistemas legados com Plone
Integração de sistemas legados com PloneFabiano Weimar
 
Mobile Summit Brazil: Ionic 2
Mobile Summit Brazil: Ionic 2Mobile Summit Brazil: Ionic 2
Mobile Summit Brazil: Ionic 2Loiane Groner
 
Nodejs - A performance que eu sempre quis ter
Nodejs - A performance que eu sempre quis terNodejs - A performance que eu sempre quis ter
Nodejs - A performance que eu sempre quis terEmerson Macedo
 
Desenvolvendo com Angular CLI
Desenvolvendo com Angular CLIDesenvolvendo com Angular CLI
Desenvolvendo com Angular CLIVanessa Me Tonini
 
Criação de aplicações web com python
Criação de aplicações web com pythonCriação de aplicações web com python
Criação de aplicações web com pythonHelder Vieira
 

Similar a Escreva aplicações web assíncronas com python3 + tornado (20)

PyData - Consumindo e publicando web APIs com Python
PyData - Consumindo e publicando web APIs com PythonPyData - Consumindo e publicando web APIs com Python
PyData - Consumindo e publicando web APIs com Python
 
Ionic Framework - Parte 1 - Iniciando um Projeto mais Robusto
Ionic Framework - Parte 1 - Iniciando um Projeto mais RobustoIonic Framework - Parte 1 - Iniciando um Projeto mais Robusto
Ionic Framework - Parte 1 - Iniciando um Projeto mais Robusto
 
Aprendendo Na Prática: Aplicativos Web com HTML5, Angular.js, Twitter Bootstr...
Aprendendo Na Prática: Aplicativos Web com HTML5, Angular.js, Twitter Bootstr...Aprendendo Na Prática: Aplicativos Web com HTML5, Angular.js, Twitter Bootstr...
Aprendendo Na Prática: Aplicativos Web com HTML5, Angular.js, Twitter Bootstr...
 
Como fazer boas libs
Como fazer boas libs Como fazer boas libs
Como fazer boas libs
 
Ionic Framework - Configuração do ambiente e a criação da primeira APP
Ionic Framework - Configuração do ambiente e a criação da primeira APPIonic Framework - Configuração do ambiente e a criação da primeira APP
Ionic Framework - Configuração do ambiente e a criação da primeira APP
 
Otimização de Aplicações Android
Otimização de Aplicações AndroidOtimização de Aplicações Android
Otimização de Aplicações Android
 
Desenvolvimento Agil Com Doctrine Orm
Desenvolvimento Agil Com Doctrine OrmDesenvolvimento Agil Com Doctrine Orm
Desenvolvimento Agil Com Doctrine Orm
 
Android 2303
Android 2303Android 2303
Android 2303
 
Apresentacao android por Júlio Cesar Bueno Cotta
Apresentacao android por Júlio Cesar Bueno CottaApresentacao android por Júlio Cesar Bueno Cotta
Apresentacao android por Júlio Cesar Bueno Cotta
 
Ionic 3
Ionic 3Ionic 3
Ionic 3
 
Como ser programador durante o dia e mesmo assim dormir bem à noite
Como ser programador durante o dia e mesmo assim dormir bem à noiteComo ser programador durante o dia e mesmo assim dormir bem à noite
Como ser programador durante o dia e mesmo assim dormir bem à noite
 
Desenvolvimento de Aplicações para o Google App Engine (CPBR5)
Desenvolvimento de Aplicações para o Google App Engine (CPBR5)Desenvolvimento de Aplicações para o Google App Engine (CPBR5)
Desenvolvimento de Aplicações para o Google App Engine (CPBR5)
 
Desenvolvimento de aplicações para o Google App Engine
Desenvolvimento de aplicações para o Google App EngineDesenvolvimento de aplicações para o Google App Engine
Desenvolvimento de aplicações para o Google App Engine
 
Tornado
TornadoTornado
Tornado
 
Integração de sistemas legados com Plone
Integração de sistemas legados com PloneIntegração de sistemas legados com Plone
Integração de sistemas legados com Plone
 
Mobile Summit Brazil: Ionic 2
Mobile Summit Brazil: Ionic 2Mobile Summit Brazil: Ionic 2
Mobile Summit Brazil: Ionic 2
 
Nodejs - A performance que eu sempre quis ter
Nodejs - A performance que eu sempre quis terNodejs - A performance que eu sempre quis ter
Nodejs - A performance que eu sempre quis ter
 
Desenvolvendo com Angular CLI
Desenvolvendo com Angular CLIDesenvolvendo com Angular CLI
Desenvolvendo com Angular CLI
 
Criação de aplicações web com python
Criação de aplicações web com pythonCriação de aplicações web com python
Criação de aplicações web com python
 
Node.js no Pagar.me
Node.js no Pagar.meNode.js no Pagar.me
Node.js no Pagar.me
 

Más de Wilson Júnior

Configurações de aplicações distribuidas com etcd
Configurações de aplicações distribuidas com etcdConfigurações de aplicações distribuidas com etcd
Configurações de aplicações distribuidas com etcdWilson Júnior
 
Pensando e Arquitetando Aplicações Resilientes
Pensando e Arquitetando Aplicações ResilientesPensando e Arquitetando Aplicações Resilientes
Pensando e Arquitetando Aplicações ResilientesWilson Júnior
 
Arquitetura de projetos e pacotes em GO
Arquitetura de projetos e pacotes em GOArquitetura de projetos e pacotes em GO
Arquitetura de projetos e pacotes em GOWilson Júnior
 
JSON Schema: Valide e navegue entre suas APIS
JSON Schema: Valide e navegue entre suas APISJSON Schema: Valide e navegue entre suas APIS
JSON Schema: Valide e navegue entre suas APISWilson Júnior
 

Más de Wilson Júnior (6)

SRE passo a passo
SRE passo a passoSRE passo a passo
SRE passo a passo
 
Configurações de aplicações distribuidas com etcd
Configurações de aplicações distribuidas com etcdConfigurações de aplicações distribuidas com etcd
Configurações de aplicações distribuidas com etcd
 
Pensando e Arquitetando Aplicações Resilientes
Pensando e Arquitetando Aplicações ResilientesPensando e Arquitetando Aplicações Resilientes
Pensando e Arquitetando Aplicações Resilientes
 
Arquitetura de projetos e pacotes em GO
Arquitetura de projetos e pacotes em GOArquitetura de projetos e pacotes em GO
Arquitetura de projetos e pacotes em GO
 
JSON Schema: Valide e navegue entre suas APIS
JSON Schema: Valide e navegue entre suas APISJSON Schema: Valide e navegue entre suas APIS
JSON Schema: Valide e navegue entre suas APIS
 
Mongoengine
MongoengineMongoengine
Mongoengine
 

Escreva aplicações web assíncronas com python3 + tornado

  • 1. Escreva aplicações web assíncronas com Python3 + Tornado Wilson Júnior
  • 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!
  • 3. Entendendo as bases do asyncronismo
  • 4. Uma aplicação pode ser dividida em 2 tempos
  • 6. CPU Bound Tempo que sua aplicação está voltada apenas para o uso do processador ...
  • 8. CPU Bound (exemplos) ● Cálculos matemáticos pesados ● Conversão de imagens ● Encoding de vídeo
  • 10. IO Bound Tempo que sua aplicação está voltada apenas para comunicação com interfaces de saída como:
  • 11. IO Bound ● Comunicação com serviços externos (banco de dados, HTTP, redis, etc) ● Comunicação com dispositivos locais (HD, Fita, DVD, pendrive, etc)
  • 12. O que acontece quando fazemos uma chamada que faz IO no python
  • 13. Exemplo de aplicação IO Bound import requests url = 'https://www.google.com.br' response = requests.get(url, timeout=10)
  • 14. Se este request HTTP demorar 10 segundos, o que acontece com a aplicação ?
  • 16. O que vem acontecendo nos últimos anos com nossas aplicações ...
  • 17. O número de clientes das aplicações mudou!
  • 18. O número de clientes das aplicações mudou!
  • 19. Otimizar o tempo de IO para alcançarmos maior número de clientes.
  • 20. Então temos o IOLoop!
  • 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
  • 22. O que um ioloop trouxe de melhoria
  • 23. As aplicações não ficam travadas em IOWait!
  • 24. Aviso sobre o conceito!
  • 25. Não bloqueie o IOLoop com operações que querem alto cpu bound!
  • 28. Aprenda a separar IO bound de CPU bound
  • 29. Podemos fazer o seguinte approach!
  • 30. Funções que fazem IO são async!
  • 31. Funções que não fazem IO são tradicionais
  • 32. Funções que fazem IO async def async_func(): # do something async
  • 33. E como pego o retorno de uma função assíncrona ?!
  • 35. Funções que fazem IO async def async_func(): # do something async async def blah(): ret = await async_func()
  • 36. Funções que fazem IO async def async_func(): # do something async async def blah(): ret = await async_func()
  • 37. Só posso fazer await dentro de outra função assíncrona!
  • 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
  • 40. Vamos começar um projetinho em tornado ?!
  • 41. Primeiro step: crie um virtualenv com python 3.6
  • 42. Primeiro step: crie um virtualenv com python 3.6 $ which python3.6 /usr/local/bin/python3.6 $ mkvirtualenv myproject -p /usr/local/bin/python3.6
  • 43. Segundo step: instale o tornado $ pip install tornado
  • 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()
  • 47. Novos imports import json from tornado.ioloop import IOLoop from tornado.web import ( Application, RequestHandler, ) from tornado.httpclient import AsyncHTTPClient
  • 48. Realizando requests async def get_http_result(): url = ( 'https://raw.githubusercontent.com' '/backstage/functions/master/package.json' ) response = await AsyncHTTPClient().fetch(url, validate_cert=False) data = json.loads(response.body) return { 'heey': data['name'], }
  • 49. Realizando requests class HelloWorldHandler(RequestHandler): async def get(self): result = await get_http_result() self.write(json.dumps(result))
  • 50. Cuidado com execução de tarefas com o uso de CPU alto
  • 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.
  • 52. Cuidado com execução de tarefas que façam IO sem usar IOLoop
  • 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')
  • 55. Teste assincronadamente import unittest from tornado.testing import AsyncTestCase, gen_test from blah import get_http_result class MyTest(AsyncTestCase): @gen_test async def test_ok(self): result = await get_http_result() self.assertEqual(result, {'heey': 'backstage-functions'})
  • 56. Teste assincronadamente $ pip install nose $ nosetests test.py
  • 57. Espere mais de uma operação assíncrona
  • 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.
  • 67. Alternativas para tarefas CPU intensive
  • 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
  • 75. Execute assincronamente via barramento (noreply)
  • 76. Tutorial: API Restful usando motor + tornado
  • 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()
  • 88. Vamos testar nossa aplicação ?!
  • 89. Vamos testar nossa aplicação ?! import json from tornado.testing import AsyncHTTPTestCase, gen_test from rest_mongo import get_app
  • 90. Vamos testar nossa aplicação ?! class MyTest(AsyncHTTPTestCase): def get_app(self): return get_app('test-database') def setUp(self): super().setUp() def drop_collection_result(*args): self.stop() self.get_app().db.drop_collection( 'people', callback=drop_collection_result) self.wait()
  • 91. Vamos testar nossa aplicação ?! class MyTest(AsyncHTTPTestCase): def test_not_found(self): response = self.fetch('/people/1234') self.assertEqual(response.code, 404) self.assertEqual(response.headers['content-type'], 'application/json') body = json.loads(response.body) self.assertEqual(body, {'error': 'Not found'})
  • 92. Vamos testar nossa aplicação ?! class MyTest(AsyncHTTPTestCase): def test_create_and_get(self): # create response = self.fetch('/people', method='POST', body='{"name": "created"}') self.assertEqual(response.code, 201) self.assertEqual(response.headers['content-type'], 'application/json') body = json.loads(response.body) self.assertEqual(body['name'], 'created')
  • 93. Vamos testar nossa aplicação ?! class MyTest(AsyncHTTPTestCase): def test_create_and_get(self): ... # get response = self.fetch('/people/%s' % body["_id"]) self.assertEqual(response.code, 200) self.assertEqual(response.headers['content-type'], 'application/json') body = json.loads(response.body) self.assertEqual(body['name'], 'created')
  • 97. Temos projetos em tornado, venha trabalhar na Globo.com talentos.globo.com Projetos