API Async Datastore (Python)

Observação: é altamente recomendável a desenvolvedores que criam novos aplicativos o uso da biblioteca de cliente NDB porque ela oferece diversos benefícios em comparação com esta biblioteca de cliente, como armazenamento automático de entidades em cache por meio da API Memcache. Se você estiver usando a antiga biblioteca de cliente de DB, leia o Guia de migração de DB para NDB

A API Async Datastore permite realizar chamadas paralelas e sem bloqueio ao armazenamento de dados e recuperar os resultados dessas chamadas em um ponto posterior no gerenciamento da solicitação. Esta documentação descreve os seguintes aspectos da API Async Datastore:

Como trabalhar com o serviço de armazenamento de dados assíncrono

Com a API de armazenamento de dados assíncrona você realiza chamadas do armazenamento de dados usando métodos do formato *_async, como o get_async () no pacote google.appengine.ext.db. O exemplo de código a seguir demonstra algumas operações simples do armazenamento de dados usando os métodos assíncronos:

from google.appengine.ext import db

get_future = db.get_async(key)
put_future = db.put_async(model)
delete_future = db.delete_async(key)
allocate_ids_future = db.allocate_ids_async(key, 10)

Essas funções realizam as mesmas operações que as versões síncronas, mas retornam imediatamente um objeto assíncrono que pode ser usado para conseguir o resultado real futuramente. O código de amostra abaixo demonstra como receber o resultado assíncrono usando get_result ():

entity = get_future.get_result()
key = put_future.get_result()
range = allocate_ids_future.get_result()

# Wait for the operation to complete without returning a value.
# Exceptions that occurred in the call are thrown here. Calling
# get_result() allows you to verify that the deletion succeeded.
delete_future.get_result()

Observação: as exceções não serão geradas até você chamar get_result(). Chamar esse método permite que você confirme o sucesso da operação assíncrona.

Como trabalhar com transações assíncronas

Chamadas da API assíncrona do armazenamento de dados podem participar de transações da mesma forma que chamadas síncronas. Veja a seguir uma função que ajusta o salário de um Employee e grava outra entidade SalaryAdjustment no mesmo grupo de entidades que Employee, tudo em uma única transação.

def adjust_salary(employee_key, raise_ammount):
   def runner():
        # Async call to lookup the Employee entity
        employee_entity_future = db.get_async(employee_key)

        # Create and put a SalaryAdjustment entity in parallel with the lookup
        adjustment_entity = SalaryAdjustment(parent=employeeKey)
        adjustment_entity.adjustment = raise_amount
        db.put_async(adjustmentEntity)

        # Fetch the result of our lookup to make the salary adjustment
        employee_entity = employee_entity_future.get_result()
        employee_entity.salary += raise_amount

        # Re-put the Employee entity with the adjusted salary.
        db.put_async(employee_entity)
    db.run_in_transaction(runner)

O exemplo ilustra uma diferença importante entre chamadas assíncronas sem transações e chamadas assíncronas dentro de transações. Quando você não usa uma transação, a única maneira de garantir que uma chamada assíncrona foi concluída é buscar o resultado do objeto assíncrono usando uma transação. Confirmar essa transação bloqueia o resultado de todas as chamadas assíncronas feitas dentro de uma transação.

Portanto, em nosso exemplo acima, mesmo que a chamada assíncrona para inserir a entidade SalaryAdjustment ainda esteja pendente ao término do runner(), não haverá confirmação até que a inserção seja concluída.

Consultas assíncronas

Atualmente não oferecemos uma API explicitamente assíncrona para consultas. No entanto, ao chamar a Query.run(), a consulta retorna imediatamente e faz uma busca prévia de resultados de forma assíncrona. Isso permite que seu aplicativo realize trabalho paralelamente enquanto resultados de consulta são buscados.

# ...

q1 = Salesperson.all().filter('date_of_hire <', one_month_ago)

# Returns instantly, query is executing in the background.
recent_hires = q1.run()

q2 = Customer.all().filter('last_contact >', one_year_ago)

# Also returns instantly, query is executing in the background.
needs_followup = q2.run()

schedule_phone_call(recent_hires, needs_followUp)

Infelizmente, Query.fetch () não tem o mesmo comportamento.

Quando usar chamadas assíncronas do armazenamento de dados

Ao chamar um método google.ext.db síncrono, como o db.get (), ele é bloqueado por seu código até que a chamada para o armazenamento de dados seja concluída. Se a única coisa que seu aplicativo precisa fazer é exibir o resultado do get() em HTML, o bloqueio até que a chamada seja concluída é uma medida perfeitamente razoável a se tomar. No entanto, caso seu aplicativo precise do resultado get(), além do resultado de uma consulta para renderizar a resposta, e o get() e a consulta não tenham dependências de dados, será perda de tempo aguardar até que o get() seja concluído para iniciar a consulta. Veja um exemplo de código que pode ser melhorado com o uso de uma API assíncrona:

# Read employee data from the Datastore
employee = Employee.get_by_key_name('Max')  # Blocking for no good reason!

# Fetch payment history
query = PaymentHistory.all().ancestor(employee.key())
history = query.fetch(10)
render_html(employee, history)

Em vez de esperar que o get() seja concluído, use db.get_async() para executar a chamada de maneira assíncrona:

employee_key = db.Key.from_path(Employee.kind(), 'Max')

# Read employee data from the Datastore
employee_future = db.get_async(employee_key)  # Returns immediately!

# Fetch payment history
query = PaymentHistory.all().ancestor(employee_key)

# Implicitly performs query asynchronously
history_itr = query.run(config=datastore_query.QueryOptions(limit=10))
employee = employee_future.get_result()
render_html(employee, history_itr)

As versões síncrona e assíncrona desse código usam quantidades de CPU semelhantes (afinal, ambas realizam a mesma quantidade de trabalho). Porém, uma vez que a versão assíncrona permite que as duas operações do armazenamento de dados sejam executadas paralelamente, ela tem latência mais baixa. Em geral, quando é necessário executar diversas operações de armazenamento de dados sem quaisquer dependências de dados, a API assíncrona melhora a latência de forma significativa.

Esta página foi útil? Conte sua opinião sobre:

Enviar comentários sobre…

Ambiente padrão do App Engine para Python 2