lru 缓存在 Flask 应用程序上相同参数的应用程序运行之间不起作用

发布于 2025-01-12 10:18:52 字数 2708 浏览 0 评论 0原文

*编辑:刚刚意识到我在函数设计中犯了一个错误,在我的 Class1 函数中重新实例化了 AppDAO ,这就是导致意外行为的原因。我通过在 cache_call 中打印 self 参数来解决这个问题。

我有一个具有以下设计的 Flask 应用程序:

 from flask import Flask, request
 from Class1 import Class1
 from AppDAO import AppDAO
 
 app = Flask(__name__)

 def main():
   app.config['appDAO'] = AppDAO()
   app.run()

 @app.route('/app_route1',methods=['POST'])
 def app_route1():
     print("Running app route 1...")
     print(app.config['appDAO'].cache_call.cache_info())
     
     cache_param = request.json.get('cached_parameter')
     print("The cached parameter is: %s." % cache_param)

     class1 = Class1(app.config['appDAO'])

     for item in ['item1', 'item2']:
           class1.do_processing(item,cache_param)

Class1.py

class Class1(object):
   def __init__(self, app_dao):
     self.app_dao = app_dao

   def do_processing(self, item, cache_param):
        print("Processing for item: %s..." % item)

        resp_cache = self.app_dao.cache_call(cache_param)
        print(self.app_dao.cache_call.cache_info())
        
        return resp_cache

AppDAO.py

from functools import lru_cache
import mysql.connector 

class AppDAO(object):
  
  def __init__():
      self.conn = mysql.connector.connect('user1','password1','server1','database')
  
  @lru_cache(maxsize=4)
  def cache_call(self, cache_param):
     print("Running cache call with parameter: %s..." % cache_param)

     cursor = self.conn.cursor()
     cursor.execute("SELECT * FROM Table1 WHERE Column1 = `%s`;" % cache_param)
     rs = cursor.fetchall()

     return rs
       

如果我运行发布帖子的应用程序,AppDAO.cache_call 使用以下输出 print 输出正确运行:

 Running app route 1...
 CacheInfo(hits=0, misses=0, maxsize=4, currsize=0)
 Processing items: item1...
 Running cache call with parameter: foo1...
 CacheInfo(hits=0, misses=1, maxsize=4, currsize=1)
 Processing items: item2...
 CacheInfo(hits=1, misses=1, maxsize=4, currsize=1)

但是我使用 cache_call 的相同参数向分支发出另一张帖子,我得到以下 print< /code> 输出:

 Running app route 1...
 CacheInfo(hits=1, misses=1, maxsize=4, currsize=1)
 Processing items: item1...
 Running cache call with parameter: foo1...
 CacheInfo(hits=1, misses=2, maxsize=4, currsize=2)
 Processing items: item2...
 CacheInfo(hits=2, misses=2, maxsize=4, currsize=2)
  

我使用以下命令运行应用程序Anaconda QT Console,但如果我也使用 Anaconda Command Prompt,我会遇到以下缓存问题。任何人都可以推测为什么当向应用程序发出新帖子时,尽管缓存的调用仍在清除中,但 lru_cache 不起作用?

*Edit: just realized I made a mistake in my function design where I re-instantiated the AppDAO in my Class1 function and that is what was causing the unexpected behavior. I figured it out by printing the self argument in cache_call.

I have a Flask App with the following design:

 from flask import Flask, request
 from Class1 import Class1
 from AppDAO import AppDAO
 
 app = Flask(__name__)

 def main():
   app.config['appDAO'] = AppDAO()
   app.run()

 @app.route('/app_route1',methods=['POST'])
 def app_route1():
     print("Running app route 1...")
     print(app.config['appDAO'].cache_call.cache_info())
     
     cache_param = request.json.get('cached_parameter')
     print("The cached parameter is: %s." % cache_param)

     class1 = Class1(app.config['appDAO'])

     for item in ['item1', 'item2']:
           class1.do_processing(item,cache_param)

Class1.py:

class Class1(object):
   def __init__(self, app_dao):
     self.app_dao = app_dao

   def do_processing(self, item, cache_param):
        print("Processing for item: %s..." % item)

        resp_cache = self.app_dao.cache_call(cache_param)
        print(self.app_dao.cache_call.cache_info())
        
        return resp_cache

AppDAO.py:

from functools import lru_cache
import mysql.connector 

class AppDAO(object):
  
  def __init__():
      self.conn = mysql.connector.connect('user1','password1','server1','database')
  
  @lru_cache(maxsize=4)
  def cache_call(self, cache_param):
     print("Running cache call with parameter: %s..." % cache_param)

     cursor = self.conn.cursor()
     cursor.execute("SELECT * FROM Table1 WHERE Column1 = `%s`;" % cache_param)
     rs = cursor.fetchall()

     return rs
       

If I run the app making a post, the AppDAO.cache_call functions correctly with the following output print output:

 Running app route 1...
 CacheInfo(hits=0, misses=0, maxsize=4, currsize=0)
 Processing items: item1...
 Running cache call with parameter: foo1...
 CacheInfo(hits=0, misses=1, maxsize=4, currsize=1)
 Processing items: item2...
 CacheInfo(hits=1, misses=1, maxsize=4, currsize=1)

But I make another post to the branch using the same parameter for the cache_call, I get the following print output:

 Running app route 1...
 CacheInfo(hits=1, misses=1, maxsize=4, currsize=1)
 Processing items: item1...
 Running cache call with parameter: foo1...
 CacheInfo(hits=1, misses=2, maxsize=4, currsize=2)
 Processing items: item2...
 CacheInfo(hits=2, misses=2, maxsize=4, currsize=2)
  

I run the app using the Anaconda QT Console, but I experience the following caching issue if I used an Anaconda Command Prompt as well. Can anyone speculate why the lru_cache is not working when a new post is made to the app despite the cached call still clearing being stored?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

花开雨落又逢春i 2025-01-19 10:18:52

请注意,这

@lru_cache(maxsize=4)
def cache_call(self, cache_param):

是包装一个方法,而不是一个函数。在您的示例中,将用作缓存键的一部分的 selfClass1 的实例,并且在每次路由处理程序调用时创建一次。结果是您没有获得预期的缓存

更新:我误读了代码。假设这

for item in [item1, item2]:

是一个拼写错误,而且应该是这样

for item in ['item1', 'item2']:

,并且您 do_processing 故意不将 item (具体情况有所不同)传递给 cache_call,那么会发生什么您看到的与 lru_cache 的行为方式一致。

在第一个请求时,它将向缓存添加一个内容 (request.json.get('cached_pa​​rameter')),将其评分为“item1”未命中和“item2”命中。

在第二个请求中,request.json.get('cached_pa​​rameter') 是一个不同的对象。添加了“item1”,将其评分为未命中(将“currsize”增加到 2)。对于“item2”,它被计为命中。

您期望什么行为?

不相关但值得一提:构建查询的方式使您容易受到 SQL 注入攻击。考虑改用绑定参数。

Note that

@lru_cache(maxsize=4)
def cache_call(self, cache_param):

is wrapping a method, not a function. In your example, self, which will be used as as part of the cache key, is an instance of Class1 and is created once per route handler invocation. The result is that you aren't getting the caching you expect.

Updated: I misread the code. Assuming that

for item in [item1, item2]:

was a typo, and should be

for item in ['item1', 'item2']:

and that you're do_processing is intentionally not passing item (which varies) to cache_call, then what you're seeing is consistent with how lru_cache behaves.

On first request, it's going to add one thing (request.json.get('cached_parameter')) to the cache, scoring it as a miss the for 'item1' and a hit for 'item2'.

On second request, request.json.get('cached_parameter') is a different object. It gets scored as a miss for 'item1', added (increasing 'currsize' to 2). For 'item2', it gets scored as a hit.

What behavior did you expect?

Unrelated but worth mentioning: The way you're constructing that query leaves you open to SQL Injection attacks. Consider using a bind parameter instead.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文