Python 2.7 已达到支持终止期限,并将于 2026 年 1 月 31 日
弃用。弃用后,您将无法部署 Python 2.7 应用,即使您的组织之前曾使用组织政策重新启用旧版运行时的部署也是如此。现有的 Python 2.7 应用在
弃用日期之后将继续运行并接收流量。我们建议您
迁移到最新支持的 Python 版本。
Async Datastore API (Python)
使用集合让一切井井有条
根据您的偏好保存内容并对其进行分类。
注意:强烈建议构建新应用的开发者使用 NDB 客户端库,它与 DB 客户端库相比具有多项优势,例如可通过 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)
此示例说明了不使用事务的异步调用与使用事务的异步调用之间的重要区别。如果您不使用事务,则确保单个异步调用已完成的唯一方法就是使用事务来提取异步对象的结果。提交该事务将阻塞在事务内执行的所有异步调用的结果。
因此,在上述示例中,即使在 runner()
完成时插入 SalaryAdjustment
实体的异步调用仍可能未完成,也无法执行提交操作,除非插入完成。
异步查询
目前,我们没有提供用于查询的显式异步 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() 不具有相同的行为。
何时使用异步数据存储区调用
如果您调用同步 google.ext.db
方法(例如 db.get()),则代码会阻塞,直到对数据存储区的调用完成。如果应用只需要以 HTML 形式呈现 get() 的结果,则在调用完成之前,执行阻塞操作是一个合理选择。然而,如果您的应用需要 get() 的结果以及 Query 的结果来呈现响应,而且 get() 和 Query 又没有任何数据依赖关系,则等待 get() 完成后再发起 Query 只是浪费时间。下面举例说明了可以通过使用异步 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 可以显著缩短延迟时间。
如未另行说明,那么本页面中的内容已根据知识共享署名 4.0 许可获得了许可,并且代码示例已根据 Apache 2.0 许可获得了许可。有关详情,请参阅 Google 开发者网站政策。Java 是 Oracle 和/或其关联公司的注册商标。
最后更新时间 (UTC):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"]],["最后更新时间 (UTC):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."]]