Async Datastore API (Python)

附註:強烈建議建構新應用程式的開發人員使用 NDB 用戶端程式庫,相較於此用戶端程式庫,NDB 用戶端程式庫有幾項優點,例如能透過 Memcache API 自動快取實體。如果您目前使用的是舊版 DB 用戶端程式庫,請參閱 DB 至 NDB 遷移指南

Async Datastore API 可讓您以平行、無阻斷的方式呼叫資料儲存庫,並在稍後處理要求時擷取這些呼叫的結果。本說明文件提供 Async Datastore API 下列方面的說明:

使用非同步資料儲存庫服務

您可以透過 Async Datastore API 使用 *_async 格式的方法發出資料儲存庫呼叫 (例如 google.appengine.ext.db 套件中的 get_async())。下列程式碼範例展示了一些使用非同步方法的簡單資料儲存庫作業。

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)

除了會立刻傳回可在稍後用來取得實際結果的非同步物件之外,這些函式和同步的版本執行一樣的作業。下列程式碼範例示範如何使用 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()

注意:在您呼叫 get_result() 之前,不會擲回例外狀況。呼叫這個方法可讓您確認非同步作業成功完成。

使用非同步交易

Async Datastore API 呼叫和同步呼叫一樣,都可在交易中使用。以下函式可調整 Employee 的薪資並在與 Employee 相同的實體群組中寫入額外的 SalaryAdjustment 實體,所有作業都在單一交易下執行。

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)

以上範例說明了「不使用交易的非同步呼叫」與「使用交易的非同步呼叫」之間的主要差異。若您不使用交易,確保獨立非同步呼叫已完成的唯一方法,便是擷取使用交易的非同步物件的結果。若修訂該交易,則會封鎖交易內的所有非同步呼叫的結果。

因此,在上述範例中,即使插入 SalaryAdjustment 實體的非同步呼叫在 runner() 完成時仍未解決,除非插入完成,否則不會進行修訂。

非同步查詢

目前,我們不開放對明確的非同步 API 進行查詢。不過,如果您叫用 Query.run(),查詢會立即傳回,並以非同步方式預先擷取結果。這會讓應用程式在擷取查詢結果時還能平行執行工作。

# ...

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)

不過,Query.fetch() 並沒有相同的行為。

非同步資料儲存庫呼叫的使用時機

當您呼叫 db.get() 等同步的 google.ext.db 方法時,在呼叫資料儲存庫完成前,程式碼都會維持封鎖狀態。如果應用程式只需將 get() 的結果轉譯成 HTML,在呼叫完成之前封鎖程式碼是相當合理的做法。不過,如果應用程式需要 get() 的結果以及查詢的結果才能轉譯回應,且 get() 與查詢之間不具有任何資料相依性,那麼等待 get() 完成才啟動查詢是相當浪費時間的做法。下列提供可透過非同步 API 提升效能的程式碼範例:

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

您可以改用 db.get_async() 以非同步方式執行呼叫,如此一來,就無需等待 get() 完成:

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)

這個程式碼的同步版和非同步版的 CPU 使用量相差不多 (畢竟這兩個版本執行的工作量相同),但由於非同步版的程式碼可以讓兩個資料儲存庫作業並行執行,所以非同步版的延遲時間較短。一般來說,如果您需要執行沒有任何資料相依性的多項資料儲存庫作業,使用非同步 API 可以明顯改善延遲情形。

本頁內容對您是否有任何幫助?請提供意見:

傳送您對下列選項的寶貴意見...

這個網頁
Python 2 適用的 App Engine 標準環境