从Django,Flask到Express(五)异步任务

Django

以下是一个 Django Celery 异步任务的示例:

首先,需要安装 Celery:

pip install celery
在项目的 settings.py 文件中配置 Celery:



CELERY_BROKER_URL = "redis://localhost:6379/0"  # 指定消息队列使用 redis
CELERY_RESULT_BACKEND = "redis://localhost:6379/1"  # 指定任务结果的存储位置
CELERY_TIMEZONE = "Asia/Shanghai"  # 指定时区
CELERY_IMPORTS = (
    "your_app.tasks",  # tasks 是存放任务的文件夹名
)

接下来,在 your_app 文件夹中创建一个 tasks.py 文件,用于存放异步任务:



from celery import shared_task

@shared_task
def add(x, y):
    return x + y
    

在视图函数中调用该任务:


from django.http import HttpResponse
from your_app.tasks import add

def my_view(request):
    result = add.delay(2, 3)  # 异步执行任务
    return HttpResponse(result.id)
    

以上示例代码的作用是将两个数相加并返回结果。调用任务时使用了 delay() 方法,该方法会将任务发送到 Celery 的消息队列中,并立即返回一个 AsyncResult 对象,这个对象包含了任务的状态信息和结果。

需要注意的是,Celery 需要启动一个 worker 进程来处理任务,启动方式为:

celery -A proj worker --loglevel=info
-A 参数指定项目名称,worker 表示启动 worker 进程,–loglevel 参数指定日志等级。

代码启动Celery

在 Django 项目的 settings.py 文件中添加以下代码,配置 Celery 使用的消息代理和结果存储位置(这里仍然使用 Redis 数据库):

CELERY_BROKER_URL = 'redis://localhost:6379/0'
CELERY_RESULT_BACKEND = 'redis://localhost:6379/0'

同时,为了让 Django 应用程序能够识别 Celery 任务,还需在 init.py 文件中定义 Celery 实例:

import os
from celery import Celery

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings')

app = Celery('myproject')
app.config_from_object('django.conf:settings', namespace='CELERY')
app.autodiscover_tasks()

上述代码中,config_from_object() 方法会将消息代理和结果存储位置配置到 Celery 实例对象中。而 autodiscover_tasks() 方法会自动发现所有已经注册的任务,并在 worker 进程中执行。

最后,在 Django 项目入口文件中启动 Celery worker 进程,例如:

from myproject import app

if __name__ == '__main__':
    app.worker_main(['worker', '--loglevel=INFO'])
    

在上述代码中,通过使用 Celery 的 worker_main() 方法来启动 Celery 的 worker 进程。

当有任务被提交到 Celery 时,它们将被分配给 worker 进程执行。需要注意的是,任务必须在 Django 项目的上下文环境中运行,因此在定义任务函数时应该使用 @app.task 装饰器来确保任务能够正确执行。

Flask

在 Flask 中使用 Celery 可以实现异步任务处理和定时任务等功能。下面是一个简单的示例来说明如何在 Flask 中使用 Celery:

首先,需要安装Celery 包:

pip install Celery
然后,创建一个 Flask 应用程序和一个 Celery 实例,例如:

from flask import Flask
from celery import Celery

app = Flask(__name__)
app.config['CELERY_BROKER_URL'] = 'redis://localhost:6379/0'
app.config['CELERY_RESULT_BACKEND'] = 'redis://localhost:6379/0'

celery = Celery(app.name, broker=app.config['CELERY_BROKER_URL'])
celery.conf.update(app.config)

在上述代码中,CELERY_BROKER_URL 和 CELERY_RESULT_BACKEND 分别设置了 Celery 使用的消息代理和结果存储位置,这里使用的是 Redis 数据库。Celery 实例的 conf 属性也被设置为 Flask 应用程序的配置文件。

接下来,在 Flask 应用程序中定义一个视图函数,使用 Celery 异步执行任务,例如:


from flask import request
from mytasks import add  # 导入自定义的任务

@app.route('/task')
def task():
    x = int(request.args.get('x'))
    y = int(request.args.get('y'))
    result = add.delay(x, y)  # 异步执行任务
    return result.id

在上述代码中,使用 Celery 的 delay() 方法将任务提交到消息代理,并返回结果的 ID。该任务将运行于一个独立的 worker 进程中。

最后,在 Flask 应用程序的入口文件中启动 Celery worker 进程,例如:

from myapp import app, celery

if __name__ == '__main__':
    with app.app_context():
        celery.worker_main(['worker', '--loglevel=INFO'])
      

在上述代码中,使用 Flask 的 app_context() 方法进入应用程序的上下文环境,然后通过执行 celery.worker_main() 启动 Celery 的 worker 进程。

注意要把任务定义、Flask 实例、Celery 实例放在同一目录下或者将任务定义导入进来。具体实现还需要根据自己的需求进行相应的调整和配置。

Express

Async

async.parallel、async.waterfall、async.series和async.auto都是Async.js中提供的异步控制流模块,用于执行一系列的异步操作。

以下是它们的异同点:

async.parallel允许多个异步操作同时执行,不需要等待前一个异步操作完成。当所有异步操作都完成后,parallel会将结果以数组形式返回。而且每个异步操作之间是相互独立的。

async.waterfall有序地执行多个异步任务,每个异步任务的输出作为下一个异步任务的输入,因此前一次执行结果可以传递到下一次执行。最终结果由最后一个异步任务提供。

async.series顺序执行多个异步操作,即先执行第一个异步操作,待第一个异步操作完成后再执行第二个异步操作,依次类推,直到所有异步操作全部完成,然后返回结果。

async.auto根据依赖自动执行多个异步操作,并确保每个异步操作只在其所有前置操作完成之后才会执行。auto会通过依赖分析来确定各个异步操作之间的关系,以此实现今日按需调度。

总体来说,这些函数都旨在帮助我们更加有效地管理异步操作,并避免“回调地狱”等复杂问题的出现。不同的函数有着不同的使用场景,选择哪种方式取决于业务需求。

下面是几个使用Async.js中异步控制流模块的示例代码:

async.parallel 的例子



const async = require('async');

async.parallel([
  function(callback) {
    setTimeout(function() {
      console.log('Task One');
      callback(null, 1);
    }, 2000);
  },
  function(callback) {
    setTimeout(function() {
      console.log('Task Two');
      callback(null, 2);
    }, 1000);
  }
],
// optional callback
function(err, results) {
  console.log(results);
});

上面的代码表示同时执行两个异步操作 Task One 和 Task Two ,分别需要2秒和1秒完成,最终返回它们的结果 [1, 2]。

async.waterfall 的例子

const async = require('async');

async.waterfall([
  function(callback) {
    callback(null, 'one', 'two');
  },
  function(arg1, arg2, callback) {
    console.log(arg1, arg2);
    callback(null, 'three');
  },
  function(arg1, callback) {
    console.log(arg1);
    callback(null, 'done');
  }
], function (err, result) {
  console.log(result);
});

上面的代码表示三个任务展开,第一个任务不需要异步操作并将两个参数传递给第二个任务;第二个任务打印出前两个参数,并将字符串“three”作为输出传递给第三个任务。 第三个任务打印“three”,然后以字符串“done”调用回调函数。

async.series 的例子

const async = require('async');

async.series([
    function(callback) {
        console.log('Task One');
        callback(null, 'one');
    },
    function(callback) {
        console.log('Task Two');
        callback(null, 'two');
    }
],
// optional callback
function(err, results) {
  console.log(results);
});

上面代码表示顺序执行两个异步操作 Task One 和 Task Two ,最终输出它们的结果 [‘one’, ‘two’]。

async.auto 的例子

const async = require('async');

async.auto({
    get_data: function(callback) {
        console.log('Task One: get_data');
        callback(null, 'data', 'converted to array');
    },
    make_folder: function(callback) {
        console.log('Task Two: make_folder');
        callback(null, 'folder');
    },
    write_file: ['get_data', 'make_folder', function(results, callback) {
        console.log('Task Three: write_file');
        console.log(results);
        callback(null, 'filename');
    }],
    email_link: ['write_file', function(results, callback) {
        console.log('Task Four: email_link');
        console.log(results);
        callback(null, {'file':results.write_file, 'email':'user@example.com'});
    }]
}, function(err, results) {
    console.log('Final callback: ',results);
});

上面的代码包含了一些有依赖关系的任务,如 make_folder 任务需要在 get_data 任务完成后才能执行,write_file 任务需要在 make_folder 和 get_data 都完成后才能执行。 最终任务 email_link 需要获取 write_file 的结果作为输入。 autoseries 等同于 auto,除了它以串行顺序执行 async 函数。 根据依赖自动执行多个异步函数,并确保每个异步函数只在其所有前置任务完成后才会执行。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值