如何使requests_cache与许多并发请求一起工作?

mch*_*hen 7 python concurrency caching python-requests

我正在获取和缓存(用于性能)大量的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)
Run Code Online (Sandbox Code Playgroud)

但是,我收到了很多错误:

sqlite3.OperationalError: database is locked
Run Code Online (Sandbox Code Playgroud)

很明显,有太多线程同时访问缓存.

那么是否requests_cache支持某种事务,以便只在所有线程完成时才发生写入?例如

with requests_cache.enabled():
    with requests_cache.transaction():
        responses = ThreadPool(100).map(requests.get, urls)
Run Code Online (Sandbox Code Playgroud)

Chr*_*ris 3

我有一个 Django-Rest-Framework 应用程序。它工作得很好,直到请求同时到来。发生这种情况时,应用程序有时会开始抛出database is locked错误。我的第一个猜测是,Django-db 过载了,需要用更强大的东西替换。

通过使用 bash 中的curl 运行并行请求来重现问题(请参阅此处),这给了我新的日志和跟踪。我发现请求缓存在清理数据库时遇到了问题。它被配置为缓存 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
Run Code Online (Sandbox Code Playgroud)

研究可能的解决方案,我发现Redis可以用作后端。我安装了 Redis 并仅在本地主机上运行它。只需将缓存配置的backendfrom设置sqlite为“redis”即可解决该问题。

我感觉有点像用锤子修理松动的螺栓,但我很高兴我在没有损坏任何东西的情况下让它工作。我确信有人能够找到更好、更优雅的解决方案,例如传递 sqlite-config-paramrequests-cache或代码修复。