十面九问的逆天异步神器-celery,你了解多少?

celery是什么,有什么用?


对于celery,各种文档解释一堆,可以自己看下,根据日常互动,公众号用户小白居多,官方用到的很多名词可能你理解起来不是那么容易,我这里就不照本宣科了,就以我这边的理解简单以下方图示解释下,如果有误,欢迎指正:


首先理解一个概念:阻塞

理解阻塞,先从耗时操作讲起,常见的场景比如用户输入、等待(sleep)这些都属于,具体到实际项目中比如说发邮件、发短信、机器/深度学习训练模型、自动化测试中的各种操作流程等待都会产生耗时,耗时操作通常我们也会称之为阻塞,意思就是程序一行一行代码执行,你这些耗时操作没执行完毕,后面的代码就不会执行,阻塞了后面的代码执行


理解了阻塞以后,就很容易引出一个问题?我如果想提高程序执行效率不让程序阻塞,那该怎么办?有没有一种方式,能在程序阻塞的时候,不影响我后面代码的执行?


一般来说,我们可以用线程、进程、协程,都是可以实现的,只不过在实际项目中,有成熟开源并且广泛应用的的东西,我们会用框架,而不去手写多线程、进程、协程,也不是说这些不用去学,这是编程的基本知识,也是必须掌握的,很能体现编程基本功底


celery基本原理:

1、客户端也就是python(django/flask等)发布任务

2、发布的任务存到任务队列里面,可以以redis、rabbitMQ、MessageQueue、MySQL存储,一般在django/flask程序里redis居多

3、任务处理者会不断从任务队列里面获取任务执行

640?wx_fmt=png

1、安装django/celery库

django==2.0.6

celery==3.1.26

django-celery==3.3.0

redis==2.10.6

都用pip安装,我这边这几个版本测试没问题,版本有些时候不兼容,如果报错,网上找下解决


2、redis数据库安装

redis安装:http://www.python88.cn/book/redis10/

注意以下几点:

1、redis.conf改bind127.0.0.1为bind 真实ip,这样可以远程访问

2、如果是阿里云服务器,需要在控制台将6379端口开放

3、redis启动服务端:redis-server,启动客户端:redis-cli


3、演示代码demo

640?wx_fmt=png

整体流程是在前面页面点击表格里面的执行,会用selenium打开浏览器,执行耗时操作,相当于每个执行都是一个单独耗时任务


4、demo前端代码:

给按钮绑定run_case2方法,获取当前表格行号(映射要用selenium打开的网站链接),作为参数传到后端


 
 
function run_case2(obj){    row_tr = obj.parentNode.parentNode.rowIndex;//获取当前行数    console.log(row_tr);    param = {"url":row_tr};    $.post('/web/yzm/', param, function (data) {    console.log(data.result)    })}
    row_tr = obj.parentNode.parentNode.rowIndex;//获取当前行数
    console.log(row_tr);
    param = {"url":row_tr};
    $.post('/web/yzm/', param, function (data{
    console.log(data.result)
    })
}


5、demo后端代码:(阻塞写法)

看下面代码,前端传的行号,我这只是为了测试传参数,随便构造的,分别跟3个网址进行映射,对于下面的这种写法,就是典型的阻塞线程,webdriver在执行的时候,只有当把quit()关闭浏览器执行完毕时候,才会return返回结果并在控制台打印success,如下图演示,我点击的是第三个执行按钮

640?wx_fmt=gif

 
 
from selenium import webdriverimport time@csrf_exempt@login_requireddef yzm(request):  url_num = request.POST.get("url")  if int(url_num)==1:    url_str = "https://www.baidu.com"   elif int(url_num==2:    url_str = "http://www.python66.cn"   elif int(url_num)==3:    url_str = "http://www.python88.cn"   print(url_num,url_str)  # 下面webdriver打开网站,并休眠5秒钟都是耗时任务   driver = webdriver.Chrome(executable_path="C:\chromedriver_win32\chromedriver.exe")   driver.get(url_str)   time.sleep(5)   driver.quit()   # 耗时任务执行完毕开始return   return JsonResponse({"result": "success"})import webdriver
import time
@csrf_exempt
@login_required
def yzm(request):
  url_num = request.POST.get("url")
  if int(url_num)==1:
    url_str = "https://www.baidu.com"
   elif int(url_num==2:
    url_str = "http://www.python66.cn"
   elif int(url_num)==3:
    url_str = "http://www.python88.cn"
   print(url_num,url_str)

  # 下面webdriver打开网站,并休眠5秒钟都是耗时任务
   driver = webdriver.Chrome(executable_path="C:\chromedriver_win32\chromedriver.exe")
   driver.get(url_str)
   time.sleep(5)
   driver.quit()

   # 耗时任务执行完毕开始return
   return JsonResponse({"result""success"})


6、demo后端代码:(celery异步)


异步:名字虽然为异步,你可以理解为同步,就是一边做耗时操作,一般执行后面代码,两者同时执行


文件目录,我在项目目录下面建立了celery_task包,创建tasks.py文件


640?wx_fmt=png


1、创建app,代表一个celery对象,broker代表队列,用的redis 0号数据库

2、然后将上一步我们selenium打开浏览器的方法封装成open_url方法

3、@app.task代表定义任务,指明这个open_url方法是一个任务,可以在视图里面调用发布


 
 
from celery import Celeryfrom selenium import webdriverimport time# 创建celery的应用app = Celery("celery_task", broker="redis://47.101.203.45:6379/0")@app.taskdef open_url(url):    driver = webdriver.Chrome(executable_path="C:\chromedriver_win32\chromedriver.exe")    driver.get(url)    time.sleep(5)    driver.quit()import Celery
from selenium import webdriver
import time

# 创建celery的应用
app = Celery("celery_task", broker="redis://47.101.203.45:6379/0")

@app.task
def open_url(url):
    driver = webdriver.Chrome(executable_path="C:\chromedriver_win32\chromedriver.exe")
    driver.get(url)
    time.sleep(5)
    driver.quit()


views.py视图里面这样写

1、from celery_task.tasks import  open_url为导入任务

2、open_url.delay(url_str)为发布任务,其中delay里面可以传参数,你前端传过来的参数views.py视图函数接收,可以再传到celery任务中去


效果图如下:当点击执行时候,return的success很快就返回并打印了,跟我操控浏览器的过程没一点牵涉,无需等待selenium,这样就实现了非阻塞异步,完美解决了耗时问题


640?wx_fmt=gif


 
 
from celery_task.tasks import open_url@csrf_exempt@login_requireddef yzm2(request): url_num = request.POST.get("url")    if int(url_num)==1: url_str = "https://www.baidu.com"    elif int(url_num)==2: url_str = "http://www.python66.cn" elif int(url_num)==3:    url_str = "http://www.python88.cn" print(url_num,url_str) open_url.delay(url_str)return JsonResponse({"result":"success"})import open_url
@csrf_exempt
@login_required
def yzm2(request):
 url_num = request.POST.get("url")
    if int(url_num)==1:
 url_str = "https://www.baidu.com"
    elif int(url_num)==2:
 url_str = "http://www.python66.cn"
 elif int(url_num)==3:
    url_str = "http://www.python88.cn"
 print(url_num,url_str)

 open_url.delay(url_str)
return JsonResponse({"result":"success"})


7、多个任务同时执行

对于多个任务同时执行,我这里连续点击三个执行按钮,立马先打印了3个success,说明3个任务都被celery异步处理了,对于多任务的参数问题,上面也说了,我们在delay里面传入参数即可,传到定义任务的tasks.py文件里面的对于方法中去,本例中我演示的是传了一个url_str参数


640?wx_fmt=gif



8、启动程序

打开两个终端,都切换到项目目录下面

1、先启动celery:

celery -A celery_task.tasks worker -l info

2、再启动django:

python manage.py runserver


本文重要的是理解原理,celery的牛逼远不止于此,有兴趣可以看看在爬虫、机器学习、深度学习领域的使用,会对celery的使用场景有更清晰的认识


python爬虫人工智能大数据公众号

640?wx_fmt=gif



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值