在处理这些问题时,你可能会遇到的最后一个问题是外部服务提供商施加的速率限制。以
使用 Google Maps API 为例,在撰写本书时,免费和未经身份验证的请求的官方费率限制为每
秒 10 个请求和每天 2,500 个请求。当使用多线程时,很容易耗尽这样的限制。更严重的问题
是,因为我们没有覆盖任何故障的场景,而处理多线程 Python 代码中的异常比平常更复杂。
当客户端超过 Google 的速率时,api.geocode()函数将抛出异常,这是个好消息。
但是这个异常是单独引发的,不会导致整个程序崩溃。工作线程当然会立即退出,但是主线
程将等待 work_queue 上存储的所有任务完成(使用 work_queue.join()调用)。这意味
着我们的工作线程应该优雅地处理可能的异常,并确保队列中的所有项目都被处理。如果不
做进一步的改进,我们可能会遇到一些情况,一些工作线程崩溃,程序永远不会退出。
让我们对我们的代码进行一些小的改动,以便为可能出现的任何问题做好准备。在工
作线程中的异常情况下,我们可以在 results_queue 队列中放置一个错误实例,并将当
前任务标记为完成,与没有错误时一样。这样,我们确保主线程在 work_queue.join()
中等待时不会无限期地锁定。主线程然后可以检查结果并重新提出在结果队列中发现的任
何异常。下面是可以以更安全的方式处理异常的 worker()和 main()函数的改进版本:
def worker(work_queue, results_queue):
while True:
try:
item = work_queue.get(block=False)
except