我正在使用以下内容获取和缓存(用于执行)大量的网址:
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)
答案 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并仅在本地主机上运行它。只需将缓存配置的backend
从sqlite
设置为“ redis”即可解决此问题。
我有点像用锤子固定松动的螺栓,但是我很高兴我能在不损坏任何东西的情况下正常工作。我相信有人会找到更好,更优雅的解决方案,例如通过requests-cache
传递sqlite-config-param或代码修复。