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

时间:2017-01-03 01:36:19

标签: python caching concurrency python-requests

我正在使用以下内容获取和缓存(用于执行)大量的网址:

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是否支持某种事务,以便只在所有线程完成时才发生写入? E.g。

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

1 个答案:

答案 0 :(得分:0)

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

通过使用bash(see here)的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

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

我有点像用锤子固定松动的螺栓,但是我很高兴我能在不损坏任何东西的情况下正常工作。我相信有人会找到更好,更优雅的解决方案,例如通过requests-cache传递sqlite-config-param或代码修复。