Post on 08-May-2015
description
Quem espera sempre Quem espera sempre cansacansaChamadas assíncronas ao Datastore PlusChamadas assíncronas ao Datastore Plus
As coisas que você deveria As coisas que você deveria sabersaber•toplevels/taskletstoplevels/tasklets
•futuresfutures
•yield (você vai fazer muitos generators)yield (você vai fazer muitos generators)
•você vai usar raise em vez de return (às vezes) você vai usar raise em vez de return (às vezes)
•não são threadsnão são threads
•..._async..._async
•a API de query mudoua API de query mudou
•Um uso insanamente legal de override de comparadoresUm uso insanamente legal de override de comparadores
Como se faziaComo se fazia
class Fact(model.Model):class Fact(model.Model): text = model.TextProperty() text = model.TextProperty() rating = model.FloatProperty(default = 400.)rating = model.FloatProperty(default = 400.) random_index = model.ComputedProperty( random_index = model.ComputedProperty(
lambda self : random.randint(0,lambda self : random.randint(0, sys.maxint))sys.maxint))
(...)(...)
for i in range(10):for i in range(10): Fact(text = 'Fact %d' % i).put() Fact(text = 'Fact %d' % i).put()
Digressão: _ah/statsDigressão: _ah/stats
•Um bom jeito de entender o desempenho de suas aplicaçõesUm bom jeito de entender o desempenho de suas aplicações
•Se você estiver fazendo algo errado, vai ficar óbvioSe você estiver fazendo algo errado, vai ficar óbvio
Fácil de ligar no app.yaml:Fácil de ligar no app.yaml:
builtins:builtins:(...)(...)- appstats: on- appstats: on
Como o código anterior se Como o código anterior se comportacomporta
… … e no servidore no servidor
O jeito assíncronoO jeito assíncrono
futures = []futures = []for i in range(10):for i in range(10): futures.append(Fact(text = 'Fact %d' % \ futures.append(Fact(text = 'Fact %d' % \
i).put_async())i).put_async())[ f.get_result() for f in futures ][ f.get_result() for f in futures ]
Dá a oportunidade de agregar os puts em uma grande operação com o Dá a oportunidade de agregar os puts em uma grande operação com o datastore (sem que tenhamos que nos preocupar muito com isso)datastore (sem que tenhamos que nos preocupar muito com isso)
_ah/stats_ah/stats
No servidorNo servidor
Fazendo melhor: Fazendo melhor: toplevel/tasklettoplevel/tasklet@context.toplevel@context.toplevel
(decorando algo que vai chamar o tasklet abaixo)(decorando algo que vai chamar o tasklet abaixo)
@tasklets.tasklet@tasklets.tasklet
def init_facts()def init_facts()
futures = []futures = [] for i in range(10): for i in range(10): futures.append(Fact(text = 'Fact %d' % \ futures.append(Fact(text = 'Fact %d' % \
i).put_async())i).put_async()) yield futures yield futures
Yield permite que o event loop do toplevel gerencie generators que estejam esperando por uma Yield permite que o event loop do toplevel gerencie generators que estejam esperando por uma resposta do servidorresposta do servidor
… … ainda melhorainda melhor
@context.toplevel@context.toplevel
(decorando o que chama o tasklet)(decorando o que chama o tasklet)
@tasklets.tasklet@tasklets.tasklet
def init_facts()def init_facts()
Futures = []Futures = []
for i in range(10):for i in range(10):
futures.append(Fact(text = 'Fact %d' \futures.append(Fact(text = 'Fact %d' \
% i).put_async())% i).put_async())
raise tasklets.Return(futures)raise tasklets.Return(futures)
Porque quando você retorna o último resultado de um iterador, você deve lançar uma exceçãoPorque quando você retorna o último resultado de um iterador, você deve lançar uma exceção
ab -n 10000 -c 50 (síncrono)ab -n 10000 -c 50 (síncrono)
Connection Times (ms)Connection Times (ms) min mean[+/-sd] median max min mean[+/-sd] median max
Connect: 140 159 69.1 145 976 Connect: 140 159 69.1 145 976 Processing: 338 7408 5452.2 6231 46247 Processing: 338 7408 5452.2 6231 46247 Waiting: 338 7407 5452.2 6230 46247 Waiting: 338 7407 5452.2 6230 46247 Total: 482 7567 5442.4 6377 46401 Total: 482 7567 5442.4 6377 46401
Percentage of the requests served within a certain time (ms)Percentage of the requests served within a certain time (ms) 50% 6377 50% 6377 66% 8540 66% 8540 75% 10131 75% 10131 80% 11068 80% 11068 90% 13419 90% 13419 95% 16077 95% 16077 98% 23883 98% 23883 99% 30173 99% 30173 100% 46401 (longest request) 100% 46401 (longest request)
ab -n 10000 -c 50 ab -n 10000 -c 50 (assíncrono)(assíncrono)Connection Times (ms)Connection Times (ms)
min mean[+/-sd] median max min mean[+/-sd] median max Connect: 140 669 1375.6 151 21193 Connect: 140 669 1375.6 151 21193 Processing: 189 338 300.0 256 15320 Processing: 189 338 300.0 256 15320 Waiting: 189 335 243.7 255 4143 Waiting: 189 335 243.7 255 4143 Total: 332 1007 1407.6 438 21450 Total: 332 1007 1407.6 438 21450
Percentage of the requests served within a certain time (ms)Percentage of the requests served within a certain time (ms) 50% 438 50% 438 66% 565 66% 565 75% 732 75% 732 80% 1272 80% 1272 90% 3372 90% 3372 95% 3456 95% 3456 98% 3762 98% 3762 99% 9366 99% 9366 100% 21450 (longest request) 100% 21450 (longest request)
Qual a diferença?Qual a diferença?
ErradoErrado
for f in Fact.query():for f in Fact.query():
f.rating = random.normalvariate(400, 20)f.rating = random.normalvariate(400, 20)
f.put() f.put()
Porque errado?Porque errado?
Certo: map_asyncCerto: map_async
@tasklets.tasklet@tasklets.taskletdef randomize_rating(f):def randomize_rating(f): f.rating = random.normalvariate(400, 20) f.rating = random.normalvariate(400, 20) raise tasklets.Return(f.put_async()) raise tasklets.Return(f.put_async())
@context.toplevel@context.topleveldef randomize_all():def randomize_all(): Fact.query().map_async(randomize_rating) Fact.query().map_async(randomize_rating)
Certo: map_asyncCerto: map_async
O que mais eu preciso O que mais eu preciso saber?saber?•context e seu event loopcontext e seu event loop
•cachescaches
•novos tipos de dadosnovos tipos de dados
•novos nomes para os tipos conhecidosnovos nomes para os tipos conhecidos
•repeated = True repeated = True
•StructuredProperty, LocalStructuredPropertyStructuredProperty, LocalStructuredProperty
•compresscompress
•tempos de resposta mais curtos e melhor uso das instânciastempos de resposta mais curtos e melhor uso das instâncias
Onde eu encontro?Onde eu encontro?
•Builds oficiaisBuilds oficiais
•http://code.google.com/p/appengine-ndb-experiment/downloads/listhttp://code.google.com/p/appengine-ndb-experiment/downloads/list
•"Bleeding" edge "Bleeding" edge
•hg clone https://code.google.com/p/appengine-ndb-experiment/hg clone https://code.google.com/p/appengine-ndb-experiment/
•Versão 0.7 foi lançada ontemVersão 0.7 foi lançada ontem
Para saber maisPara saber mais
•Documentação:Documentação:
http://code.google.com/p/appengine-ndb-experiment/http://code.google.com/p/appengine-ndb-experiment/
•Google Group:Google Group:
http://groups.google.com/group/appengine-ndb-discuss/http://groups.google.com/group/appengine-ndb-discuss/
AgradecimentosAgradecimentos
Agradecimentos são devidos ao pessoal do grupo appengine-ndb-discuss, Agradecimentos são devidos ao pessoal do grupo appengine-ndb-discuss, em especial ao Guido e ao Vladimir, que sugeriram assuntos e me em especial ao Guido e ao Vladimir, que sugeriram assuntos e me apontaram na direção certa.apontaram na direção certa.