
在使用 Eel 框架进行 Python 与前端交互时,经常会遇到需要在 Python 函数执行过程中更新前端页面的情况,例如动态加载图片。然而,如果 Python 函数执行时间过长,可能会阻塞前端页面的渲染,导致图片无法及时显示,直到 Python 函数执行完毕。这严重影响了用户体验。本文将介绍一种使用 Celery 异步任务队列解决此问题的方案。
问题分析
当 Python 函数通过 eel.expose 暴露给前端 JavaScript 调用时,实际上是在 WSGI 服务器上执行的。如果该函数执行时间过长,WSGI 服务器会一直等待该函数返回,才能将响应发送给前端。因此,前端页面会一直处于等待状态,无法及时渲染和加载图片。
解决方案:使用 Celery 异步任务队列
立即学习“Python免费学习笔记(深入)”;
Celery 是一个强大的分布式任务队列,可以用于异步执行耗时任务。通过将耗时任务放入 Celery 任务队列中执行,可以避免阻塞主线程,从而确保前端页面能够及时响应。
具体步骤
-
安装 Celery 和 Redis
Celery 需要一个消息中间件来传递任务,这里我们选择 Redis。
pip install celery redis
-
创建 Celery 任务
创建一个 celery.py 文件,配置 Celery 实例:
from celery import Celery celery_app = Celery('my_app', broker='redis://localhost:6379/0', # Redis 作为消息中间件 backend='redis://localhost:6379/0') # Redis 作为结果存储 celery_app.conf.update( task_serializer='pickle', result_serializer='pickle', accept_content=['pickle', 'json'], result_expires=3600, ) @celery_app.task def long_running_task(source, keyword): # code that takes a long time to execute 2 # 在这里执行耗时操作,例如图像处理、数据分析等 # 可以将结果保存到文件或数据库中 import time time.sleep(5) # 模拟耗时操作 return f"Processed {source} with {keyword}" -
修改 Python 代码
将 generate 函数修改为调用 Celery 任务:
import eel from celery import Celery celery_app = Celery('my_app', broker='redis://localhost:6379/0', # Redis 作为消息中间件 backend='redis://localhost:6379/0') # Redis 作为结果存储 celery_app.conf.update( task_serializer='pickle', result_serializer='pickle', accept_content=['pickle', 'json'], result_expires=3600, ) @celery_app.task def long_running_task(source, keyword): # code that takes a long time to execute 2 # 在这里执行耗时操作,例如图像处理、数据分析等 # 可以将结果保存到文件或数据库中 import time time.sleep(5) # 模拟耗时操作 return f"Processed {source} with {keyword}" @eel.expose def generate(source, keyword): # code that takes a long time to execute 1 eel.set_image() long_running_task.delay(source, keyword) # 异步执行耗时任务 return # 立即返回 -
启动 Celery worker
在终端中启动 Celery worker:
celery -A celery_app worker -l info
-
修改前端代码
前端代码保持不变,只需要确保 set_image() 函数能够及时被调用。
eel.expose(set_image); function set_image() { document.getElementById("zoom-animate").innerHTML = '@@##@@'; } function generate() { let source = document.getElementById("source").value; let keyword = document.getElementById("keyword").value; eel.generate(source, keyword); }
代码解释
- long_running_task.delay(source, keyword): delay 方法用于异步执行 Celery 任务,并将 source 和 keyword 作为参数传递给任务函数。
- eel.set_image(): 该函数用于通知前端加载图片,应该在调用 long_running_task.delay() 之前执行,以确保图片能够及时显示。
- return: generate 函数在调用 long_running_task.delay() 后立即返回,避免阻塞主线程。
注意事项
- 确保 Redis 服务器已启动。
- Celery worker 需要在后台运行,以便能够处理异步任务。
- 如果需要在前端获取 Celery 任务的结果,可以使用 Celery 的 result 对象。
- 对于更复杂的任务,可以使用 Celery 的任务链和工作流。
- 确保 celery_app 的配置正确,特别是 broker 和 backend 的地址。
总结
通过使用 Celery 异步任务队列,我们可以有效地解决在使用 Eel 框架进行 Python 与前端交互时,由于长时间运行的 Python 函数阻塞了前端页面的渲染,导致图片无法及时加载的问题。该方案不仅可以提高用户体验,还可以提高应用程序的性能和可扩展性。 通过将耗时任务异步化,可以使前端页面更加流畅,响应更加迅速。










