geekdoc-python-zh/docs/realpython/caching-external-api-reques...

6.6 KiB
Raw Permalink Blame History

缓存外部 API 请求

原文:https://realpython.com/caching-external-api-requests/

有没有发现自己对一个外部 API 发出完全相同的请求,使用完全相同的参数并返回完全相同的结果?如果是这样,那么您应该缓存这个请求来限制 HTTP 请求的数量,以帮助提高性能。

让我们看一个使用请求包的例子。

Github API

Github repo 中抓取代码(或者下载 zip )。基本上,我们一遍又一遍地搜索 Github API根据位置和编程语言寻找相似的开发者:

url = "https://api.github.com/search/users?q=location:{0}+language:{1}".format(first, second)
response_dict = requests.get(url).json()

现在,在初始搜索之后,如果用户再次搜索(例如,不改变参数),应用程序将执行完全相同的搜索,一次又一次地点击 Github API。由于这是一个昂贵的过程它减慢了我们的最终用户的应用程序。此外通过像这样打几个电话我们可以很快用完我们的速率限制。

幸运的是,有一个简单的解决方法。

Remove ads

请求-缓存

为了实现缓存,我们可以使用一个名为 Requests-cache 的简单包,它是一个“用于请求的透明持久缓存”。

请记住,您可以将这个包用于任何 Python 框架,而不仅仅是 Flask 或脚本,只要您将它与 requests 包结合使用。

首先安装软件包:

$ pip install --upgrade requests-cache

然后将导入添加到 app.py 以及install_cache()方法中:

requests_cache.install_cache(cache_name='github_cache', backend='sqlite', expire_after=180)

现在无论何时使用requests,响应都会被自动缓存。此外,您可以看到我们正在定义几个选项。注意expire_after选项,它被设置为 180 秒。由于 Github API 经常更新,我们希望确保交付最新的结果。因此,在初始缓存发生 180 秒后,请求将重新触发并缓存一组新的结果,提供更新的结果。

更多选项,请查看官方文档

所以您的 app.py 文件现在应该是这样的:

import requests
import requests_cache

from flask import Flask, render_template, request, jsonify

app = Flask(__name__)

requests_cache.install_cache('github_cache', backend='sqlite', expire_after=180)

@app.route('/', methods=['GET', 'POST'])
def home():
    if request.method == 'POST':
        first = request.form.get('first')
        second = request.form.get('second')
        url = "https://api.github.com/search/users?q=location:{0}+language:{1}".format(first, second)
        response_dict = requests.get(url).json()
        return jsonify(response_dict)
    return render_template('index.html')

if __name__ == '__main__':
    app.run(debug=True)

测试!

启动应用程序搜索开发者。在“app”目录中应该创建一个名为 github_cache.sqliteSQLite 数据库。现在,如果您继续使用相同的位置和编程语言进行搜索,requests实际上不会进行调用。相反,它将使用来自 SQLite 数据库的缓存响应。

让我们确保缓存确实过期了。像这样更新home()视图功能:

@app.route('/', methods=['GET', 'POST'])
def home():
    if request.method == 'POST':
        first = request.form.get('first')
        second = request.form.get('second')
        url = "https://api.github.com/search/users?q=location:{0}+language:{1}".format(first, second)
        now = time.ctime(int(time.time()))
        response = requests.get(url)
        print "Time: {0} / Used Cache: {1}".format(now, response.from_cache)
        return jsonify(response.json())
    return render_template('index.html')

因此,这里我们只是使用from_cache属性来查看响应是否来自缓存。让我们来测试一下。尝试新的搜索。然后打开你的终端:

Time: Fri Nov 28 13:34:25 2014 / Used Cache: False

所以你可以看到我们在 13:34:25 向 Github API 发出了初始请求,由于False被输出到屏幕上,所以没有使用缓存。再次尝试搜索。

Time: Fri Nov 28 13:35:28 2014 / Used Cache: True

现在您可以看到使用了缓存。多试几次。

Time: Fri Nov 28 13:36:10 2014 / Used Cache: True
Time: Fri Nov 28 13:37:59 2014 / Used Cache: False
Time: Fri Nov 28 13:39:09 2014 / Used Cache: True

所以您可以看到缓存过期了,我们在 13:37:59 进行了一个新的 API 调用。之后就用缓存了。简单吧?

当您更改请求中的参数时会发生什么试试看。输入新的位置和编程语言。这里发生了什么因为参数改变了Requests-cache 把它当作不同的请求,不使用缓存。

Remove ads

平衡-同花顺与性能

同样,在上面的示例中,我们在 180 秒后终止缓存(通常称为刷新),以便向最终用户交付最新的数据。想一想。

真的有必要那么定时冲吗?大概不会。在这个应用程序中,我们可以将这个时间更改为 5 分钟或 10 分钟,因为如果我们偶尔错过一些添加到 API 中的新用户,这并不是什么大问题。

也就是说,当数据对时间敏感并且对应用程序的核心功能至关重要时,您确实需要密切关注刷新。

例如,如果您从一个每分钟更新几次的 API(如地震活动 API )中提取数据,并且您的最终用户必须拥有最新的数据,那么您可能希望每隔 30 或 60 秒左右使其过期。

平衡刷新频率和调用时间也很重要。如果您的 API 调用相当昂贵——可能需要一到五秒——那么您希望增加刷新之间的时间来提高性能。

结论

缓存是一个强大的工具。在这种情况下,我们通过限制外部 HTTP 请求的数量来提高应用程序的性能。我们从实际的 HTTP 请求本身中去掉了延迟。

在很多情况下,你不仅仅是在提出请求。您还必须处理请求,这可能涉及访问数据库、执行某种过滤等。因此,缓存也可以减少请求处理的延迟。

想要本教程的代码吗?抓住它这里。干杯!**