Python 2.7 已終止支援,並將於 2026 年 1 月 31 日
淘汰。淘汰後,您將無法部署 Python 2.7 應用程式,即使貴機構先前曾使用機構政策重新啟用舊版執行階段的部署作業,也無法部署。現有的 Python 2.7 應用程式在
淘汰日期過後,仍會繼續執行並接收流量。建議您
改用系統支援的最新 Python 版本。
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
方法時,在呼叫資料儲存庫完成前,程式碼都會維持封鎖狀態。如果應用程式只需要在 HTML 中轉譯 get() 的結果,那麼等待呼叫完成再執行其他動作,是相當合理的做法。不過,如果應用程式需要結合 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 可以明顯改善延遲情形。
除非另有註明,否則本頁面中的內容是採用創用 CC 姓名標示 4.0 授權,程式碼範例則為阿帕契 2.0 授權。詳情請參閱《Google Developers 網站政策》。Java 是 Oracle 和/或其關聯企業的註冊商標。
上次更新時間:2025-09-04 (世界標準時間)。
[[["容易理解","easyToUnderstand","thumb-up"],["確實解決了我的問題","solvedMyProblem","thumb-up"],["其他","otherUp","thumb-up"]],[["難以理解","hardToUnderstand","thumb-down"],["資訊或程式碼範例有誤","incorrectInformationOrSampleCode","thumb-down"],["缺少我需要的資訊/範例","missingTheInformationSamplesINeed","thumb-down"],["翻譯問題","translationIssue","thumb-down"],["其他","otherDown","thumb-down"]],["上次更新時間:2025-09-04 (世界標準時間)。"],[[["\u003cp\u003eDevelopers should prioritize the NDB Client Library over the older DB Client Library for new applications due to benefits like automatic entity caching.\u003c/p\u003e\n"],["\u003cp\u003eThe Async Datastore API enables parallel, non-blocking calls to the datastore, using methods like \u003ccode\u003e*_async\u003c/code\u003e (e.g., \u003ccode\u003eget_async()\u003c/code\u003e, \u003ccode\u003eput_async()\u003c/code\u003e), which return asynchronous objects to retrieve results later.\u003c/p\u003e\n"],["\u003cp\u003eAsync datastore calls can be used within transactions, and transaction commits will block until all async calls within that transaction have completed.\u003c/p\u003e\n"],["\u003cp\u003eQueries using \u003ccode\u003eQuery.run()\u003c/code\u003e return immediately and asynchronously prefetch results, allowing parallel work, unlike \u003ccode\u003eQuery.fetch()\u003c/code\u003e.\u003c/p\u003e\n"],["\u003cp\u003eUsing the asynchronous API for multiple, independent datastore operations can significantly reduce latency by allowing parallel execution compared to sequential synchronous calls.\u003c/p\u003e\n"]]],[],null,["# Async Datastore API (Python)\n\n**Note:**\nDevelopers building new applications are **strongly encouraged** to use the\n[NDB Client Library](/appengine/docs/legacy/standard/python/ndb), which has several benefits\ncompared to this client library, such as automatic entity caching via the Memcache\nAPI. If you are currently using the older DB Client Library, read the\n[DB to NDB Migration Guide](/appengine/docs/legacy/standard/python/ndb/db_to_ndb)\n\n\nThe Async Datastore API allows you to make parallel, non-blocking calls to the datastore and to retrieve the results of these calls at a later point in the handling of the request. This documentation describes the following aspects of the Async Datastore API:\n\nWorking with the Async Datastore Service\n----------------------------------------\n\n\nWith the async datastore API, you make datastore calls using methods of the form `*_async` (such as [get_async()](/appengine/docs/legacy/standard/python/datastore/functions#get_async) in the `google.appengine.ext.db` package). The following code sample demonstrates some simple datastore operations using the asynchronous methods: \n\n```python\nfrom google.appengine.ext import db\n\nget_future = db.get_async(key)\nput_future = db.put_async(model)\ndelete_future = db.delete_async(key)\nallocate_ids_future = db.allocate_ids_async(key, 10)\n```\n\nThese functions perform the same operations as the synchronous versions, except they immediately return an asynchronous object that you can use to get the real result at some later point. The following code sample demonstrates how to get the asynchronous result using [get_result()](/appengine/docs/legacy/standard/python/issue-requests#issuing_an_asynchronous_request):\n\n```python\nentity = get_future.get_result()\nkey = put_future.get_result()\nrange = allocate_ids_future.get_result()\n\n# Wait for the operation to complete without returning a value.\n# Exceptions that occurred in the call are thrown here. Calling\n# get_result() allows you to verify that the deletion succeeded.\ndelete_future.get_result()\n```\n\n**Note:** Exceptions are not thrown until you call get_result(). Calling this method allows you to verify that the async operation succeeded.\n\nWorking with Async Transactions\n-------------------------------\n\n\nAsync datastore API calls can participate in transactions just like synchronous calls. Here's a function that adjusts the salary of an `Employee` and writes an additional `SalaryAdjustment` entity in the same entity group as the `Employee`, all within a single transaction. \n\n```python\ndef adjust_salary(employee_key, raise_ammount):\n def runner():\n # Async call to lookup the Employee entity\n employee_entity_future = db.get_async(employee_key)\n\n # Create and put a SalaryAdjustment entity in parallel with the lookup\n adjustment_entity = SalaryAdjustment(parent=employeeKey)\n adjustment_entity.adjustment = raise_amount\n db.put_async(adjustmentEntity)\n\n # Fetch the result of our lookup to make the salary adjustment\n employee_entity = employee_entity_future.get_result()\n employee_entity.salary += raise_amount\n\n # Re-put the Employee entity with the adjusted salary.\n db.put_async(employee_entity)\n db.run_in_transaction(runner)\n```\n\n\nThis sample illustrates an important difference between async calls with no transactions and async calls within transactions. When you are not using a transaction, the only way to ensure that an individual async call has completed is to fetch the result of the async object using a transaction. Committing that transaction blocks on the result of all async calls made within a transaction.\n\n\nSo, in our example above, even though our async call to insert the `SalaryAdjustment` entity may still be outstanding when `runner()` finishes, the commit will not happen until the insert completes.\n\nAsync Queries\n-------------\n\n\nWe do not currently expose an explicitly async API for queries. However, when you invoke [Query.run()](/appengine/docs/legacy/standard/python/datastore/queryclass#Query_run), the query immediately returns and asynchronously prefetches results. This allows your application to perform work in parallel while query results are fetched. \n\n```python\n# ...\n\nq1 = Salesperson.all().filter('date_of_hire \u003c', one_month_ago)\n\n# Returns instantly, query is executing in the background.\nrecent_hires = q1.run()\n\nq2 = Customer.all().filter('last_contact \u003e', one_year_ago)\n\n# Also returns instantly, query is executing in the background.\nneeds_followup = q2.run()\n\nschedule_phone_call(recent_hires, needs_followUp)\n```\n\n\nUnfortunately, [Query.fetch()](/appengine/docs/legacy/standard/python/datastore/queryclass#Query_fetch) does not have the same behavior.\n\nWhen To Use Async Datastore Calls\n---------------------------------\n\n\nWhen you call a synchronous `google.ext.db` method, such as [db.get()](/appengine/docs/legacy/standard/python/datastore/functions#get), your code blocks until the call to the datastore completes. If the only thing your application needs to do is render the result of the get() in HTML, blocking until the call is complete is a perfectly reasonable thing to do. However, if your application needs the result of the get() plus the result of a Query to render the response---and if the get() and the Query don't have any data dependencies---then waiting until the get() completes to initiate the Query is a waste of time. Here is an example of some code that can be improved by using the async API: \n\n```python\n# Read employee data from the Datastore\nemployee = Employee.get_by_key_name('Max') # Blocking for no good reason!\n\n# Fetch payment history\nquery = PaymentHistory.all().ancestor(employee.key())\nhistory = query.fetch(10)\nrender_html(employee, history)\n```\n\n\nInstead of waiting for the get() to complete, use db.get_async() to execute the call asynchronously: \n\n```python\nemployee_key = db.Key.from_path(Employee.kind(), 'Max')\n\n# Read employee data from the Datastore\nemployee_future = db.get_async(employee_key) # Returns immediately!\n\n# Fetch payment history\nquery = PaymentHistory.all().ancestor(employee_key)\n\n# Implicitly performs query asynchronously\nhistory_itr = query.run(config=datastore_query.QueryOptions(limit=10))\nemployee = employee_future.get_result()\nrender_html(employee, history_itr)\n```\n\n\nThe synchronous and asynchronous versions of this code use similar amounts of CPU (after all, they both perform the same amount of work), but since the asynchronous version allows the two datastore operations to execute in parallel, the asynchronous version has lower latency. In general, if you need to perform multiple datastore operations that don't have any data dependencies, the asynchronous API can significantly improve latency."]]