Datastore API Asinkron (Python)

Catatan: Developer yang membuat aplikasi baru sangat dianjurkan untuk menggunakan Library Klien NDB, yang memiliki beberapa manfaat dibandingkan dengan library klien ini, seperti menyimpan entity dalam cache secara otomatis melalui Memcache API. Jika saat ini Anda menggunakan Library Klien DB versi lama, baca Panduan Migrasi DB ke NDB

Datastore API Asinkron memungkinkan Anda untuk melakukan panggilan paralel yang tidak memblokir ke datastore dan mengambil hasil panggilan ini di lain waktu dalam menangani permintaan. Dokumentasi ini menjelaskan aspek-aspek Datastore API Asinkron berikut:

Bekerja dengan Layanan Datastore Asinkron

Dengan datastore API asinkron, Anda melakukan panggilan datastore menggunakan metode bentuk *_async (seperti get_async() dalam paket google.appengine.ext.db). Contoh kode berikut menunjukkan beberapa operasi datastore sederhana menggunakan metode asinkron:

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)

Fungsi ini menjalankan operasi yang sama seperti versi sinkron, tetapi fungsi ini langsung menampilkan objek asinkron yang dapat Anda gunakan untuk mendapatkan hasil nyata di lain waktu. Contoh kode berikut menunjukkan cara mendapatkan hasil asinkron menggunakan 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()

Catatan: Pengecualian tidak akan ditampilkan hingga Anda memanggil get_result(). Memanggil metode ini memungkinkan Anda memverifikasi bahwa operasi asinkron berhasil.

Bekerja dengan Transaksi Asinkron

Panggilan API datastore asinkron dapat berperan dalam transaksi sama seperti panggilan sinkron. Berikut adalah fungsi yang menyesuaikan gaji Employee dan menulis entity SalaryAdjustment tambahan dalam entity group yang sama dengan Employee, semuanya dalam satu transaksi.

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)

Contoh ini menggambarkan perbedaan penting antara panggilan asinkron tanpa transaksi dan panggilan asinkron dalam transaksi. Saat Anda tidak menggunakan transaksi, satu-satunya cara untuk memastikan bahwa panggilan asinkron individual telah selesai adalah dengan mengambil hasil objek asinkron menggunakan transaksi. Melakukan pemblokiran transaksi tersebut pada hasil semua panggilan asinkron yang dilakukan dalam transaksi.

Jadi, dalam contoh di atas, meskipun panggilan asinkron untuk menyisipkan entity SalaryAdjustment mungkin masih belum terselesaikan saat runner() selesai, commit tidak akan terjadi hingga penyisipan selesai.

Kueri Asinkron

Saat ini kami tidak mengekspos API yang asinkron secara eksplisit untuk kueri. Namun, saat Anda memanggil Query.run(), kueri akan segera menampilkan dan mengambil data hasil secara asinkron. Hal ini memungkinkan aplikasi Anda melakukan pekerjaan secara paralel saat hasil kueri diambil.

# ...

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)

Sayangnya, Query.fetch() tidak memiliki perilaku yang sama.

Kapan Menggunakan Panggilan Datastore Asinkron

Saat Anda memanggil metode google.ext.db sinkron, seperti db.get(), kode Anda akan memblokir hingga panggilan ke datastore selesai. Jika satu-satunya hal yang perlu dilakukan aplikasi Anda adalah merender hasil get() dalam HTML, memblokir hingga panggilan selesai adalah hal yang sangat masuk akal untuk dilakukan. Namun, jika aplikasi Anda memerlukan hasil get() ditambah hasil Query untuk merender respons—dan jika get() dan Kueri tidak memiliki dependensi data—menunggu hingga get() selesai memulai Kueri itu hanyalah menghabiskan waktu. Berikut adalah contoh beberapa kode yang dapat diperbaiki menggunakan API asinkron:

# 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)

Daripada menunggu get() selesai, gunakan db.get_async() untuk mengeksekusi panggilan secara asinkron:

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)

Versi sinkron dan asinkron dari kode ini menggunakan CPU dalam jumlah yang sama (lagipula, keduanya melakukan jumlah pekerjaan yang sama), tetapi karena versi asinkron memungkinkan dua operasi datastore dijalankan secara paralel, versi asinkron memiliki latensi yang lebih rendah. Secara umum, jika Anda perlu melakukan beberapa operasi datastore yang tidak memiliki dependensi data, API asinkron dapat meningkatkan latensi secara signifikan.