如何使requests_cache能够处理多个并发请求?

13

我正在获取并缓存(以提高性能)许多URL,大致如下:

import requests
import requests_cache
from multiprocessing.pool import ThreadPool

urls = ['http://www.google.com', ...]
with requests_cache.enabled():
    responses = ThreadPool(100).map(requests.get, urls)

然而,我为以下内容收到了许多错误信息:

sqlite3.OperationalError: database is locked

显然,太多的线程同时访问缓存。

那么requests_cache是否支持某种事务,以便在所有线程完成后才进行写操作?例如:

with requests_cache.enabled():
    with requests_cache.transaction():
        responses = ThreadPool(100).map(requests.get, urls)
2个回答

3

因为requests.cache.enabled()及其相关函数使用monkey-patching,所以它不支持线程安全。

但幸运的是,执行所有实际缓存操作的基础类(CachedSession)从requests-cache 0.6+开始就支持线程安全(在0.7+中进一步改进),所以这可能是你想在这里使用的。这里有一个使用ThreadPoolExecutor的完整示例:https://github.com/reclosedev/requests-cache/blob/master/examples/threads.py

像其他答案提到的那样,Redis将是并发请求的更好选择,但并不是必需的。SQLite足够处理并发,它支持无限并发读取,但并发写入会在内部排队并按顺序运行。在许多情况下,这仍然足够快,你甚至都不会注意到,但如果你要处理大量并发写入,则Redis或其他后端之一将更优化。


3
我有一个Django-Rest-Framework应用程序。它运行得非常完美,但当同时有请求进来时,应用程序有时会开始抛出“数据库已锁定”的错误。我的第一个猜测是,Django-db负载过重,需要用更强大的东西替换它。
通过从bash中使用curl运行并行请求(参见此处)来复现该问题,给了我新鲜的日志和跟踪信息。我发现,requests-cache在清理其数据库时遇到了问题。它被配置为缓存600秒,因此在填充缓存后的第一批运行将始终失败:
...
File "/opt/app/lib/python3.5/site-packages/requests_cache/core.py" in remove_expired_responses
159.         self.cache.remove_old_entries(datetime.utcnow() - self._cache_expire_after)

File "/opt/app/lib/python3.5/site-packages/requests_cache/backends/base.py" in remove_old_entries
117.             self.delete(key)

File "/opt/app/lib/python3.5/site-packages/requests_cache/backends/base.py" in delete
83.                 del self.responses[key]

File "/opt/app/lib/python3.5/site-packages/requests_cache/backends/storage/dbdict.py" in __delitem__
130.                               self.table_name, (key,))

Exception Type: OperationalError at /app/v1/invitations/
Exception Value: database is locked

在寻找可能的解决方案时,我发现可以使用Redis作为后端。我安装了Redis并仅在本地主机上运行。只需将缓存配置中的backendsqlite更改为“redis”即可解决问题。

我感觉有点像用锤子修复松动的螺栓,但我很高兴我成功了而没有破坏任何东西。我相信有人能够找到更好、更优雅的解决方案,比如通过requests-cache传递一个sqlite-config-param或者进行代码修复。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接