Quem espera sempre
cansa
Chamadas assíncronas ao Datastore Plus
As coisas que você deveria
saber
•toplevels/tasklets

•futures

•yield (você vai fazer muitos generators)

•você vai usar raise em vez de return (às vezes)

•não são threads

•..._async

•a API de query mudou

•Um uso insanamente legal de override de comparadores
Como se fazia

class Fact(model.Model):
    text = model.TextProperty()
    rating = model.FloatProperty(default = 400.)
    random_index = model.ComputedProperty(
        lambda self : random.randint(0,
            sys.maxint))
(...)
for i in range(10):
    Fact(text = 'Fact %d' % i).put()
Digressão: _ah/stats

•Um bom jeito de entender o desempenho de suas aplicações

•Se você estiver fazendo algo errado, vai ficar óbvio



Fácil de ligar no app.yaml:



builtins:
(...)
- appstats: on
Como o código anterior se
comporta
… e no servidor
O jeito assíncrono

futures = []
for i in range(10):
    futures.append(Fact(text = 'Fact %d' % 

        i).put_async())
[ f.get_result() for f in futures ]

 

Dá a oportunidade de agregar os puts em uma grande operação com o
datastore (sem que tenhamos que nos preocupar muito com isso)
_ah/stats
No servidor
Fazendo melhor:
toplevel/tasklet
@context.toplevel
(decorando algo que vai chamar o tasklet abaixo)

 

@tasklets.tasklet
def init_facts()
  futures = []
  for i in range(10):
    futures.append(Fact(text = 'Fact %d' % 
      i).put_async())
  yield futures
 

Yield permite que o event loop do toplevel gerencie generators que estejam esperando por uma
resposta do servidor
… ainda melhor
@context.toplevel
(decorando o que chama o tasklet)



@tasklets.tasklet
def init_facts()
     Futures = []
     for i in range(10):
           futures.append(Fact(text = 'Fact %d' 
                 % i).put_async())
     raise tasklets.Return(futures)
Porque quando você retorna o último resultado de um iterador, você deve lançar uma exceção
ab -n 10000 -c 50 (síncrono)
Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:      140  159  69.1    145     976
Processing:   338 7408 5452.2   6231   46247
Waiting:      338 7407 5452.2   6230   46247
Total:        482 7567 5442.4   6377   46401

Percentage of the requests served within a certain time (ms)
  50%   6377
  66%   8540
  75%  10131
  80%  11068
  90%  13419
  95%  16077
  98%  23883
  99%  30173
 100%  46401 (longest request)
ab -n 10000 -c 50
(assíncrono)
Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:      140  669 1375.6    151   21193
Processing:   189  338 300.0    256   15320
Waiting:      189  335 243.7    255    4143
Total:         332 1007 1407.6    438   21450

Percentage of the requests served within a certain time (ms)
  50%    438
  66%    565
  75%    732
  80%   1272
  90%   3372
  95%   3456
  98%   3762
  99%   9366
 100%  21450 (longest request)
Qual a diferença?
Errado


for f in Fact.query():
   f.rating = random.normalvariate(400, 20)
   f.put()
Porque errado?
Certo: map_async

@tasklets.tasklet
def randomize_rating(f):
  f.rating = random.normalvariate(400, 20)
  raise tasklets.Return(f.put_async())

@context.toplevel
def randomize_all():
  Fact.query().map_async(randomize_rating)
Certo: map_async
O que mais eu preciso
saber?
•context e seu event loop

•caches

•novos tipos de dados

•novos nomes para os tipos conhecidos

•repeated = True

•StructuredProperty, LocalStructuredProperty

•compress

•tempos de resposta mais curtos e melhor uso das instâncias
Onde eu encontro?


•Builds oficiais

•http://code.google.com/p/appengine-ndb-experiment/downloads/list

•"Bleeding" edge

•hg clone https://code.google.com/p/appengine-ndb-experiment/

•Versão 0.7 foi lançada ontem
Para saber mais


•Documentação:

 http://code.google.com/p/appengine-ndb-experiment/

•Google Group:

 http://groups.google.com/group/appengine-ndb-discuss/
Agradecimentos



Agradecimentos são devidos ao pessoal do grupo appengine-ndb-discuss,
em especial ao Guido e ao Vladimir, que sugeriram assuntos e me
apontaram na direção certa.

Quem espera sempre cansa

  • 1.
    Quem espera sempre cansa Chamadasassíncronas ao Datastore Plus
  • 2.
    As coisas quevocê deveria saber •toplevels/tasklets •futures •yield (você vai fazer muitos generators) •você vai usar raise em vez de return (às vezes) •não são threads •..._async •a API de query mudou •Um uso insanamente legal de override de comparadores
  • 3.
    Como se fazia classFact(model.Model):     text = model.TextProperty()     rating = model.FloatProperty(default = 400.)     random_index = model.ComputedProperty(         lambda self : random.randint(0,             sys.maxint)) (...) for i in range(10):     Fact(text = 'Fact %d' % i).put()
  • 4.
    Digressão: _ah/stats •Um bomjeito de entender o desempenho de suas aplicações •Se você estiver fazendo algo errado, vai ficar óbvio Fácil de ligar no app.yaml: builtins: (...) - appstats: on
  • 5.
    Como o códigoanterior se comporta
  • 6.
    … e noservidor
  • 7.
    O jeito assíncrono futures= [] for i in range(10):     futures.append(Fact(text = 'Fact %d' %         i).put_async()) [ f.get_result() for f in futures ]   Dá a oportunidade de agregar os puts em uma grande operação com o datastore (sem que tenhamos que nos preocupar muito com isso)
  • 8.
  • 9.
  • 10.
    Fazendo melhor: toplevel/tasklet @context.toplevel (decorando algoque vai chamar o tasklet abaixo)   @tasklets.tasklet def init_facts()   futures = []   for i in range(10):     futures.append(Fact(text = 'Fact %d' %       i).put_async())   yield futures   Yield permite que o event loop do toplevel gerencie generators que estejam esperando por uma resposta do servidor
  • 11.
    … ainda melhor @context.toplevel (decorandoo que chama o tasklet) @tasklets.tasklet def init_facts() Futures = [] for i in range(10): futures.append(Fact(text = 'Fact %d' % i).put_async()) raise tasklets.Return(futures) Porque quando você retorna o último resultado de um iterador, você deve lançar uma exceção
  • 12.
    ab -n 10000-c 50 (síncrono) Connection Times (ms)               min  mean[+/-sd] median   max Connect:      140  159  69.1    145     976 Processing:   338 7408 5452.2   6231   46247 Waiting:      338 7407 5452.2   6230   46247 Total:        482 7567 5442.4   6377   46401 Percentage of the requests served within a certain time (ms)   50%   6377   66%   8540   75%  10131   80%  11068   90%  13419   95%  16077   98%  23883   99%  30173  100%  46401 (longest request)
  • 13.
    ab -n 10000-c 50 (assíncrono) Connection Times (ms)               min  mean[+/-sd] median   max Connect:      140  669 1375.6    151   21193 Processing:   189  338 300.0    256   15320 Waiting:      189  335 243.7    255    4143 Total:         332 1007 1407.6    438   21450 Percentage of the requests served within a certain time (ms)   50%    438   66%    565   75%    732   80%   1272   90%   3372   95%   3456   98%   3762   99%   9366  100%  21450 (longest request)
  • 14.
  • 15.
    Errado for f inFact.query(): f.rating = random.normalvariate(400, 20) f.put()
  • 16.
  • 17.
    Certo: map_async @tasklets.tasklet def randomize_rating(f):  f.rating = random.normalvariate(400, 20)   raise tasklets.Return(f.put_async()) @context.toplevel def randomize_all():   Fact.query().map_async(randomize_rating)
  • 18.
  • 19.
    O que maiseu preciso saber? •context e seu event loop •caches •novos tipos de dados •novos nomes para os tipos conhecidos •repeated = True •StructuredProperty, LocalStructuredProperty •compress •tempos de resposta mais curtos e melhor uso das instâncias
  • 20.
    Onde eu encontro? •Buildsoficiais •http://code.google.com/p/appengine-ndb-experiment/downloads/list •"Bleeding" edge •hg clone https://code.google.com/p/appengine-ndb-experiment/ •Versão 0.7 foi lançada ontem
  • 21.
    Para saber mais •Documentação: http://code.google.com/p/appengine-ndb-experiment/ •Google Group: http://groups.google.com/group/appengine-ndb-discuss/
  • 22.
    Agradecimentos Agradecimentos são devidosao pessoal do grupo appengine-ndb-discuss, em especial ao Guido e ao Vladimir, que sugeriram assuntos e me apontaram na direção certa.