精华内容
下载资源
问答
  • 职业生涯规划理论篇PPT以挖掘自身潜藏的能力为核心,致力于为你提供最实用的职业生涯规划理论篇PPT,赶快...该文档为职业生涯规划理论篇PPT,是一份很不错的参考资料,具有较高参考价值,感兴趣的可以下载看看
  • 一分钟经理——理论篇以挖掘自身潜藏的能力为核心,致力于为你提供最实用的一分钟经理——理论篇,赶快来...该文档为一分钟经理——理论篇,是一份很不错的参考资料,具有较高参考价值,感兴趣的可以下载看看
  • 用户画像理论篇

    2017-12-08 19:28:21
    用户画像理论篇,告诉你怎么做好用户画像分析,用户网络行为画像读书笔记。
  • CPU超频指南之理论篇.pdf
  • 逻辑回归 - 理论篇

    万次阅读 多人点赞 2014-07-16 15:42:14
    此文章为初学机器学习时,对Andrew NG《机器学习》课程整理所写,也参考了其他CSDN同学的笔记,写的较为粗糙,很多网友帮助我指正了问题,现在重新更新向量化部分,并加入实践。 什么是逻辑回归? Logistic回归...

    此文章为初学机器学习时,对Andrew NG《机器学习》课程整理所写,也参考了其他CSDN同学的笔记,写的较为粗糙,很多网友帮助我指正了问题,现在重新更新向量化部分,并加入实践篇。


    什么是逻辑回归?

    Logistic回归与多重线性回归实际上有很多相同之处,最大的区别就在于它们的因变量不同,其他的基本都差不多。正是因为如此,这两种回归可以归于同一个家族,即广义线性模型(generalizedlinear model)。

    这一家族中的模型形式基本上都差不多,不同的就是因变量不同。

    • 如果是连续的,就是多重线性回归;
    • 如果是二项分布,就是Logistic回归;
    • 如果是Poisson分布,就是Poisson回归;
    • 如果是负二项分布,就是负二项回归。

    Logistic回归的因变量可以是二分类的,也可以是多分类的,但是二分类的更为常用,也更加容易解释。所以实际中最常用的就是二分类的Logistic回归。

    Logistic回归的主要用途:

    • 寻找危险因素:寻找某一疾病的危险因素等;
    • 预测:根据模型,预测在不同的自变量情况下,发生某病或某种情况的概率有多大;
    • 判别:实际上跟预测有些类似,也是根据模型,判断某人属于某病或属于某种情况的概率有多大,也就是看一下这个人有多大的可能性是属于某病。

    Logistic回归主要在流行病学中应用较多,比较常用的情形是探索某疾病的危险因素,根据危险因素预测某疾病发生的概率,等等。例如,想探讨胃癌发生的危险因素,可以选择两组人群,一组是胃癌组,一组是非胃癌组,两组人群肯定有不同的体征和生活方式等。这里的因变量就是是否胃癌,即“是”或“否”,自变量就可以包括很多了,例如年龄、性别、饮食习惯、幽门螺杆菌感染等。自变量既可以是连续的,也可以是分类的。

     

    常规步骤

    Regression问题的常规步骤为:

    1. 寻找h函数(即hypothesis);
    2. 构造J函数(损失函数);
    3. 想办法使得J函数最小并求得回归参数(θ)

    构造预测函数h

    Logistic回归虽然名字里带“回归”,但是它实际上是一种分类方法,主要用于两分类问题(即输出只有两种,分别代表两个类别),所以利用了Logistic函数(或称为Sigmoid函数),函数形式为:

    Sigmoid 函数在有个很漂亮的“S”形,如下图所示(引自维基百科):

     

    下面左图是一个线性的决策边界,右图是非线性的决策边界。

     

    对于线性边界的情况,边界形式如下:

    构造预测函数为:

    函数的值有特殊的含义,它表示结果取1的概率,因此对于输入x分类结果为类别1和类别0的概率分别为:

     

    构造损失函数J

    Cost函数和J函数如下,它们是基于最大似然估计推导得到的。

     

    下面详细说明推导的过程:

    (1)式综合起来可以写成:

    取似然函数为:

    对数似然函数为:

    最大似然估计就是求使取最大值时的θ,其实这里可以使用梯度上升法求解,求得的θ就是要求的最佳参数。但是,在Andrew Ng的课程中将取为下式,即:

    因为乘了一个负的系数-1/m,所以取最小值时的θ为要求的最佳参数。

     

    梯度下降法求的最小值

    θ更新过程:

    θ更新过程可以写成:

    向量化Vectorization

    Vectorization是使用矩阵计算来代替for循环,以简化计算过程,提高效率。

    如上式,Σ(...)是一个求和的过程,显然需要一个for语句循环m次,所以根本没有完全的实现vectorization。

    下面介绍向量化的过程:

    假设模型:

    公式为:

    将上述公式向量化:

    其中 ,由于(h-y)维度是m*1,X也是m*1,所以需对X转置。

    具体推导过程请参考:Vectorized Logistic Regression

     

    正则化Regularization

    过拟合问题

    对于线性回归或逻辑回归的损失函数构成的模型,可能会有些权重很大,有些权重很小,导致过拟合(就是过分拟合了训练数据),使得模型的复杂度提高,泛化能力较差(对未知数据的预测能力)。

    下面左图即为欠拟合,中图为合适的拟合,右图为过拟合。

     

    问题的主因

    过拟合问题往往源自过多的特征。

    解决方法

    1)减少特征数量(减少特征会失去一些信息,即使特征选的很好)

    • 可用人工选择要保留的特征;
    • 模型选择算法;

    2)正则化(特征较多时比较有效)

    • 保留所有特征,但减少θ的大小

     

    正则化方法

    正则化是结构风险最小化策略的实现,是在经验风险上加一个正则化项或惩罚项。正则化项一般是模型复杂度的单调递增函数,模型越复杂,正则化项就越大。

    从房价预测问题开始,这次采用的是多项式回归。左图是适当拟合,右图是过拟合。

     

    直观来看,如果我们想解决这个例子中的过拟合问题,最好能将的影响消除,也就是让。假设我们对进行惩罚,并且令其很小,一个简单的办法就是给原有的Cost函数加上两个略大惩罚项,例如:

    这样在最小化Cost函数的时候,

    正则项可以取不同的形式,在回归问题中取平方损失,就是参数的L2范数,也可以取L1范数。取平方损失时,模型的损失函数变为:

     

    lambda是正则项系数:

    • 如果它的值很大,说明对模型的复杂度惩罚大,对拟合数据的损失惩罚小,这样它就不会过分拟合数据,在训练数据上的偏差较大,在未知数据上的方差较小,但是可能出现欠拟合的现象;
    • 如果它的值很小,说明比较注重对训练数据的拟合,在训练数据上的偏差会小,但是可能会导致过拟合。

    正则化后的梯度下降算法θ的更新变为:

    正则化后的线性回归的Normal Equation的公式为:

     

    其他优化算法

    • Conjugate gradient method(共轭梯度法)
    • Quasi-Newton method(拟牛顿法)
    • BFGS method
    • L-BFGS(Limited-memory BFGS)

    后二者由拟牛顿法引申出来,与梯度下降算法相比,这些算法的优点是:

    • 第一,不需要手动的选择步长;
    • 第二,通常比梯度下降算法快;

    但是缺点是更复杂。

     

    多类分类问题

    对于多类分类问题,可以将其看做成二类分类问题:保留其中的一类,剩下的作为另一类。

    对于每一个类 i 训练一个逻辑回归模型的分类器,并且预测y = i时的概率;对于一个新的输入变量x, 分别对每一个类进行预测,取概率最大的那个类作为分类结果:

      

    参考链接

     http://blog.csdn.net/dongtingzhizi/article/details/15962797

    Coursera公开课笔记: 斯坦福大学机器学习第六课“逻辑回归(Logistic Regression)”

    Coursera公开课笔记: 斯坦福大学机器学习第七课“正则化(Regularization)” 

    Vectorized Logistic Regression
     

    展开全文
  • 物流专业讲座之物流理论篇.pptx
  • 分镜头脚本的创作理论篇.doc
  • 全面质量管理基本知识理论篇.ppt
  • C# 面试题之理论篇

    2009-05-29 12:30:20
    C#面试题之理论篇C#面试题之理论篇C#面试题之理论篇C#面试题之理论篇C#面试题之理论篇C#面试题之理论篇
  • 本课程总体分为两大部分:理论篇与架构篇 一: AssetBundle理论篇:      主要讲解Unity基于2017版本AssetBundle整体构建理论与详细示意图。      Unity原生打包、创建、...
  • 【EJB】理论篇

    2017-04-09 21:55:43
    如题,关于EJB的理论篇哦~
           如题,关于EJB的理论篇哦~
    展开全文
  • HCIE-R&S理论篇.pdf

    2019-06-19 17:11:41
    HCIE-R&S网络技术理论篇,学懂了这本128页文档。网络工程技术学通了8成,后面的2成靠项目经验积累了。
  • 理论篇揭秘大数据存储基石HDFS-理论篇.pptx
  • 00927 注册纳税筹划师培训课程理论篇(PPT 53页).ppT
  • Flutter开发指南之理论篇:Dart语法01(数据类型,变量,函数) Flutter开发指南之理论篇:Dart语法02(运算符,循环,异常) Flutter开发指南之理论篇:Dart语法03(类,泛型) Flutter开发指南之理论篇:Dart语法...

    总目录

    Flutter开发指南之理论篇:Dart语法01(数据类型,变量,函数)
    Flutter开发指南之理论篇:Dart语法02(运算符,循环,异常)
    Flutter开发指南之理论篇:Dart语法03(类,泛型)
    Flutter开发指南之理论篇:Dart语法04(库,异步,正则表达式)
    Flutter开发指南之理论篇:Dart语法05(单线程模型,事件循环模型,Isolate)
    Flutter开发指南之理论篇:Flutter基础01(架构,设计思想)


     Dart是一门面向对象语言,它针对web 和移动设备开发进行了优化,主要特点为:

    • 一切皆对象!无论是数字,函数还是null,所有对象继承自Object类;
    • 声明一个变量时可以不指定具体类型,Dart可以自动推断类型;
    • Dart支持顶层函数,函数是一等对象,且函数可作为参数传递;
    • Dart使用_开头表示私有属性,没有关键字publicprotectedprivate

    1. 单线程模型

     众所周知,在Java中使用多线程来处理并发任务,适量并合适地使用多线程,能够极大地提高资源的利用率和程序运行效率,但是缺点也比较明显,比如过度开启线程会带来额外的资源和性能消耗多线程共享内存容易出现死锁等。实际上,在APP的使用过程中,多数处理空闲状态,并不需要进行密集或高并发的处理,因此从某些意义上来说,多线程显得有点多余。正是因为如此,Dart作为一种新的语言,通过引单线程模型很好地处理了并发任务对多线程的依赖。

    1.1 单线程模型

     Dart是一种单线程语言,因此Dart程序没有主线程和子线程之分,而在Dart中线程并不是指Thread,而是指Isolate。因为Dart没有线程的概念,只有Isolate,每个Isolate都是隔离的,并不会共享内存。所有的Dart代码都是在Isolate中运行,它就像机器上的一个小空间,具有自己的私有内存块和一个运行着事件循环模型的单线程。也就是说,一旦某个Dart函数开始执行,它将执行到这个函数的结束而不被其他Dart代码打断,这就是单线程的特性。

    image

     默认情况下,Dart程序只有一个Isolate(未自己创建的情况下),而这个Isolate就是Main Isolate。也就是说,一个Dart程序是从Main Isolate的main函数开始的,而在main函数结束后,Main isolate线程开始一个一个处理事件循环模型队列中的每一事件(Event)。上图描述的就是Main Isolate的消息循环模型。

    1.2 事件循环模型

     也许你会问,既然Dart是一种单线程语言,那么是不是就意味着Dart无法并发处理异步任务了?此言差矣。前面说到,所有的Dart程序都在Isolate中运行,每个Isolate拥有自己的私有内存块和一个事件循环模型,其中,事件循环模型就是用来处理各种事件,比如点输入/输出,点击,定时器以及异步任务等。下图描述了一个Isolate事件循环模型的整个流程:

    在这里插入图片描述

     从上图可知,Dart事件循环机制由一个消息循环(event looper)两个消息队列构成,其中,两个消息队列是指事件队列(event queue)微任务队列(Microtask queue)。该机制运行原理为:

    • 首先,Dart程序从main函数开始运行,待main函数执行完毕后,event looper开始工作;
    • 然后,event looper优先遍历执行Microtask队列所有事件,直到Microtask队列为空;
    • 接着,event looper才遍历执行Event队列中的所有事件,直到Event队列为空;
    • 最后,视情况退出循环。

     为了进一步理解,我们解释下上述三个概念:

    (1)消息循环(Event Looper)

     顾名思义,消息循环就是指一个永不停歇且不能阻塞的循环,它将不停的尝试从微任务队列事件队列中获取事件(event)进行处理,而这些Event包括了用户输入,点击,Timer,文件IO等。

    在这里插入图片描述

    (2)事件队列(Event queue)

     该队列的事件来源于外部事件Future,其中,外部事件主要包括I/O,手势,绘制,计时器和isolate相互通信的message等,而Future主要是指用户自定义的异步任务,通过创建Future类实例来向事件队列添加事件。需要注意的是,当Event looper正在处理Microtask Queue时,Event queue会被阻塞,此时APP将无法进行UI绘制,响应用户输入和I/O等事件。下列示例演示了向Event queue中添加一个异步任务事件:

    main(List<String> args) {
      print('main start...')
      
      var futureInstance = Future<String>(() => "12345");
      futureInstance.then((res) {
        print(res);
      }).catchError((err) {
        print(err);
      });
      
      print('main end...')
    }
    
    // 打印结果:
    //      main start...
    //      main end...
    //      12345
    

    (3)微任务队列(Microtask queue)

     该队列的事件来源与当前isolate的内部或通过scheduleMicrotask函数创建,Microtask一般用于非常短的内部异步动作,并且任务量非常少,如果微任务非常多,就会造成Event queue排不上队,会阻塞Event queue的执行造成应用ANR,因为Microtask queue的优先级高于Event queue。因此,大多数情况下的任务优先考虑使用Event queue,不到万不得已不要使用Microtask queue。下列示例演示了两个事件队列执行情况:

    import 'dart:async';
    main() {
      print('main #1 of 2');
      scheduleMicrotask(() => print('microtask #1 of 2'));
    
      new Future.delayed(new Duration(seconds:1),
                         () => print('future #1 (delayed)'));
      new Future(() => print('future #2 of 3'));
      new Future(() => print('future #3 of 3'));
    
      scheduleMicrotask(() => print('microtask #2 of 2'));
    
      print('main #2 of 2');
    }
    
    // 执行结果:
    //      main #1 of 2
    //      main #2 of 2
    //      microtask #1 of 2
    //      microtask #2 of 2
    //      future #2 of 3
    //      future #3 of 3
    //      future #1 (delayed)
    

    2. Isolate

     大多数计算机中,甚至在移动平台上,都在使用多核CPU。 为了有效利用多核性能,开发者一般使用共享内存数据来保证多线程的正确执行。 然而多线程共享数据通常会导致很多潜在的问题,并导致代码运行出错。Dart作为一种新语言,为了缓解上述问题,提出了Isolate(隔离区)的概念,即Dart没有线程的概念,只有Isolate,所有的Dart代码都是在Isolate中运行,它就像是机器上的一个小空间,具有自己的私有内存堆和一个运行着Event Looper的单个线程。

    在这里插入图片描述

     通常,一个Dart应用对应着一个Main Isolate,且应用的入口即为该Isolate的main函数。当然,我们也可以创建其它的Isolate,由于Isolate的内存堆是私有的,因此这些Isolate的内存都不会被其它Isolate访问。假如不同的Isolate需要通信(单向/双向),就只能通过向对方的事件循环队列里写入任务,并且它们之间的通讯方式是通过port(端口)实现的,其中,Port又分为receivePort(接收端口)sendPort(发送端口),它们是成对出现的。Isolate之间通信过程:

    • 首先,当前Isolate创建一个ReceivePort对象,并获得对应的SendPort对象;
     var receivePort = ReceivePort();
     var sendPort = receivePort.sendPort;
    
    • 其次,创建一个新的Isolate,并实现新Isolate要执行的异步任务,同时,将当前Isolate的SendPort对象传递给新的Isolate,以便新Isolate使用这个SendPort对象向原来的Isolate发送事件;
    // 调用Isolate.spawn创建一个新的Isolate
    // 这是一个异步操作,因此使用await等待执行完毕
    var anotherIsolate = await Isolate.spawn(otherIsolateInit, receivePort.sendPort);
    
    // 新Isolate要执行的异步任务
    // 即调用当前Isolate的sendPort向其receivePort发送消息
    void otherIsolateInit(SendPort sendPort) async {
      value = "Other Thread!";
      sendPort.send("BB");
    }
    
    • 第三,调用当前Isolate#receivePort的listen方法监听新的Isolate传递过来的数据。Isolate之间什么数据类型都可以传递,不必做任何标记。
    receivePort.listen((date) {
        print("Isolate 1 接受消息:data = $date");
    });
    
    • 最后,消息传递完毕,关闭新创建的Isolate。
    anotherIsolate?.kill(priority: Isolate.immediate);
    anotherIsolate =null;
    

    示例代码如下(Isolate单向通信):

    import 'dart:isolate';
    
    var anotherIsolate;
    var value = "Now Thread!";
    
    void startOtherIsolate() async {
      var receivePort = ReceivePort();
    
      anotherIsolate = await Isolate.spawn(otherIsolateInit, receivePort.sendPort);
    
      receivePort.listen((date) {
        print("Isolate 1 接受消息:data = $date,value = $value");
      });
    }
    
    void otherIsolateInit(SendPort sendPort) async {
      value = "Other Thread!";
      sendPort.send("BB");
    }
    
    // 在Main Isolate创建一个新的Isolate
    // 并使用Main Isolate的ReceiverPort接收新Isolate传递过来的数据
    import 'DartLib.dart';
    
    void main(){
      startOtherIsolate();
    }
    

     执行结果:

    Isolate 1 接受消息:data = BB,value = Now Thread!
    

    3. 参考文献

    1. Dart asynchronous programming: Isolates and event loops
    2. Futures - Isolates - Event Loop
    3. Flutter 真异步

    展开全文
  • 非线性系统的多项式近似表示及电力系统应用(Ⅰ)——理论篇.pdf
  • VC++6.0 socket编程基础(理论篇)
  • 如何构建一个分布式爬虫:理论篇

    千次阅读 2017-05-22 09:28:37
    前言本系列文章计划分三个章节进行讲述,分别是理论篇、基础篇和实战篇。理论篇主要为构建分布式爬虫而储备的理论知识,基础篇会基于理论篇的知识写一个简易的分布式爬虫,实战篇则会以微博为例,教大家做一个比较...

    前言

    本系列文章计划分三个章节进行讲述,分别是理论篇、基础篇和实战篇。理论篇主要为构建分布式爬虫而储备的理论知识,基础篇会基于理论篇的知识写一个简易的分布式爬虫,实战篇则会以微博为例,教大家做一个比较完整且足够健壮的分布式微博爬虫。通过这三篇文章,希望大家能掌握如何构建一个分布式爬虫的方法;能举一反三,将celery用于除爬虫外的其它场景。目前基本上的博客都是教大家使用scrapyd或者scrapy-redis构建分布式爬虫,本系列文章会从另外一个角度讲述如何用requests+celery构建一个健壮的、可伸缩并且可扩展的分布式爬虫。

    本系列文章属于爬虫进阶文章,期望受众是具有一定Python基础知识和编程能力、有爬虫经验并且希望提升自己的同学。小白要是感兴趣,也可以看看,看不懂的话,可以等有了一定基础和经验后回过头来再看。

    另外一点说明,本系列文章不是旨在构建一个分布式爬虫框架或者分布式任务调度框架,而是利用现有的分布式任务调度工具来实现分布式爬虫,所以请轻喷。

    分布式爬虫概览

    1. 何谓分布式爬虫?
      通俗的讲,分布式爬虫就是多台机器多个 spider 对多个 url 的同时处理问题,分布式的方式可以极大提高程序的抓取效率。

    2. 构建分布式爬虫通畅需要考虑的问题
      (1)如何能保证多台机器同时抓取同一个URL?
      (2)如果某个节点挂掉,会不会影响其它节点,任务如何继续?
      (3)既然是分布式,如何保证架构的可伸缩性和可扩展性?不同优先级的抓取任务如何进行资源分配和调度?

    基于上述问题,我选择使用celery作为分布式任务调度工具,是分布式爬虫中任务和资源调度的核心模块。它会把所有任务都通过消息队列发送给各个分布式节点进行执行,所以可以很好的保证url不会被重复抓取;它在检测到worker挂掉的情况下,会尝试向其他的worker重新发送这个任务信息,这样第二个问题也可以得到解决;celery自带任务路由,我们可以根据实际情况在不同的节点上运行不同的抓取任务(在实战篇我会讲到)。本文主要就是带大家了解一下celery的方方面面(有celery相关经验的同学和大牛可以直接跳过了)

    Celery知识储备

    celery基础讲解

    按celery官网的介绍来说

    Celery 是一个简单、灵活且可靠的,处理大量消息的分布式系统,并且提供维护这样一个系统的必需工具。它是一个专注于实时处理的任务队列,同时也支持任务调度。

    下面几个关于celery的核心知识点

    1. broker:翻译过来叫做中间人。它是一个消息传输的中间件,可以理解为一个邮箱。每当应用程序调用celery的异步任务的时候,会向broker传递消息,而后celery的worker将会取到消息,执行相应程序。这其实就是消费者和生产者之间的桥梁。
    2. backend: 通常程序发送的消息,发完就完了,可能都不知道对方时候接受了。为此,celery实现了一个backend,用于存储这些消息以及celery执行的一些消息和结果。
    3. worker: Celery类的实例,作用就是执行各种任务。注意在celery3.1.25后windows是不支持celery worker的!
    4. producer: 发送任务,将其传递给broker
    5. beat: celery实现的定时任务。可以将其理解为一个producer,因为它也是通过网络调用定时将任务发送给worker执行。注意在windows上celery是不支持定时任务的!

    下面是关于celery的架构示意图,结合上面文字的话应该会更好理解

    celery架构示意图

    由于celery只是任务队列,而不是真正意义上的消息队列,它自身不具有存储数据的功能,所以broker和backend需要通过第三方工具来存储信息,celery官方推荐的是 RabbitMQRedis,另外mongodb等也可以作为broker或者backend,可能不会很稳定,我们这里选择Redis作为broker兼backend。

    关于redis的安装和配置可以查看这里

    实际例子

    先安装celery

    pip install celery

    我们以官网给出的例子来做说明,并对其进行扩展。首先在项目根目录下,这里我新建一个项目叫做celerystudy,然后切换到该项目目录下,新建文件tasks.py,然后在其中输入下面代码

    from celery import Celery
    
    app = Celery('tasks', broker='redis://:''@223.129.0.190:6379/2', backend='redis://:''@223.129.0.190:6379/3')
    
    @app.task
    def add(x, y):
        return x + y

    这里我详细讲一下代码:我们先通过app=Celery()来实例化一个celery对象,在这个过程中,我们指定了它的broker,是redis的db 2,也指定了它的backend,是redis的db3, broker和backend的连接形式大概是这样

    redis://:password@hostname:port/db_number

    然后定义了一个add函数,重点是@app.task,它的作用在我看来就是**将add()
    注册为一个类似服务的东西,本来只能通过本地调用的函数被它装饰后,就可以通过网络来调用。这个tasks.py中的app就是一个worker。它可以有很多任务,比如这里的任务函数add。我们再通过在命令行切换到项目根目录**,执行

    celery -A tasks worker -l info

    启动成功后就是下图所示的样子

    celery的worker启动成功

    这里我说一下各个参数的意思,-A指定的是app(即Celery实例)所在的文件模块,我们的app是放在tasks.py中,所以这里是 tasks;worker表示当前以worker的方式运行,难道还有别的方式?对的,比如运行定时任务就不用指定worker这个关键字; -l info表示该worker节点的日志等级是info,更多关于启动worker的参数(比如-c-Q等常用的)请使用

    celery worker –help

    进行查看

    将worker启动起来后,我们就可以通过网络来调用add函数了。我们在后面的分布式爬虫构建中也是采用这种方式分发和消费url的。在命令行先切换到项目根目录,然后打开python交互端

    from tasks import add
    rs = add.delay(2, 2) # 这里的add.delay就是通过网络调用将任务发送给add所在的worker执行

    这个时候我们可以在worker的界面看到接收的任务和计算的结果。

    [2017-05-19 14:22:43,038: INFO/MainProcess] Received task: tasks.add[c0dfcd0b-d05f-4285-b944-0a8aba3e7e61] # worker接收的任务

    [2017-05-19 14:22:43,065: INFO/MainProcess] Task tasks.add[c0dfcd0b-d05f-4285-b944-0a8aba3e7e61] succeeded in 0.025274309000451467s: 4 # 执行结果

    这里是异步调用,如果我们需要返回的结果,那么要等rsready状态true才行。这里add看不出效果,不过试想一下,如果我们是调用的比较占时间的io任务,那么异步任务就比较有价值了

    rs #

    rs.ready() # true 表示已经返回结果了

    rs.status # ‘SUCCESS’ 任务执行状态,失败还是成功

    rs.successful() # True 表示执行成功

    rs.result # 4 返回的结果

    rs.get() # 4 返回的结果

    from tasks import add
    
    if __name__ == '__main__':
        add.delay(5, 10)

    这时候可以在celery的worker界面看到执行的结果

    [2017-05-19 14:25:48,039: INFO/MainProcess] Received task: tasks.add[f5ed0d5e-a337-45a2-a6b3-38a58efd9760]
    [2017-05-19 14:25:48,074: INFO/MainProcess] Task tasks.add[f5ed0d5e-a337-45a2-a6b3-38a58efd9760] succeeded in 0.03369094600020617s: 15

    此外,我们还可以通过send_task()来调用,将excute_tasks.py改成这样

    from tasks import app
    if __name__ == '__main__':
        app.send_task('tasks.add', args=(10, 15),)

    这种方式也是可以的。send_task()还可能接收到为注册(即通过@app.task装饰)的任务,这个时候worker会忽略这个消息

    [2017-05-19 14:34:15,352: ERROR/MainProcess] Received unregistered task of type ‘tasks.adds’.
    The message has been ignored and discarded.

    定时任务

    上面部分讲了怎么启动worker和调用worker的相关函数,这里再讲一下celery的定时任务。

    爬虫由于其特殊性,可能需要定时做增量抓取,也可能需要定时做模拟登陆,以防止cookie过期,而celery恰恰就实现了定时任务的功能。在上述基础上,我们将tasks.py文件改成如下内容

    from celery import Celery
    app = Celery('add_tasks', broker='redis:''//223.129.0.190:6379/2', backend='redis:''//223.129.0.190:6379/3')
    app.conf.update(
       #  配置所在时区 
        CELERY_TIMEZONE='Asia/Shanghai',
        CELERY_ENABLE_UTC=True,
        #  官网推荐消息序列化方式为json 
        CELERY_ACCEPT_CONTENT=['json'],
        CELERY_TASK_SERIALIZER='json',
        CELERY_RESULT_SERIALIZER='json',
       # 配置定时任务
        CELERYBEAT_SCHEDULE={
            'my_task': {
                'task': 'tasks.add',  # tasks.py模块下的add方法
                'schedule': 60,      # 每隔60运行一次
                'args': (23, 12),
            }
        }
    )
    @app.task
    def add(x, y):
        return x + y

    然后先通过ctrl+c停掉前一个worker,因为我们代码改了,需要重启worker才会生效。我们再次以celery -A tasks worker -l info这个命令开启worker。

    这个时候我们只是开启了worker,如果要让worker执行任务,那么还需要通过beat给它定时发送,我们再开一个命令行,切换到项目根目录,通过

    celery beat -A tasks -l info

    celery beat v3.1.25 (Cipater) is starting.
    __    -    ... __   -        _
    Configuration ->
        . broker -> redis://223.129.0.190:6379/2
        . loader -> celery.loaders.app.AppLoader
        . scheduler -> celery.beat.PersistentScheduler
        . db -> celerybeat-schedule
        . logfile -> [stderr]@%INFO
        . maxinterval -> now (0s)
    [2017-05-19 15:56:57,125: INFO/MainProcess] beat: Starting...

    这样就表示定时任务已经开始运行了。

    眼尖的同学可能看到我这里celery的版本是3.1.25,这是因为celery支持的windows最高版本是3.1.25。由于我的分布式微博爬虫的worker也同时部署在了windows上,所以我选择了使用 3.1.25。如果全是linux系统,建议使用celery4。

    此外,还有一点需要注意,在celery4后,定时任务(通过schedule调度的会这样,通过crontab调度的会马上执行)会在当前时间再过定时间隔执行第一次任务,比如我这里设置的是60秒的间隔,那么第一次执行add会在我们通过celery beat -A tasks -l info启动定时任务后60秒才执行;celery3.1.25则会马上执行该任务。

    关于定时任务更详细的请看官方文档celery定时任务


    至此,我们把构建一个分布式爬虫的理论知识都讲了一遍,主要就是对于celery的了解和使用,这里并未涉及到celery的一些高级特性,实战篇可能会讲解一些我自己使用的特性。

    下一篇我将介绍如何使用celery写一个简单的分布式爬虫,希望大家能有所收获。


    此外,打一个广告,我写了一个分布式的微博爬虫,主要就是利用celery做的分布式实战篇我也将会以该项目其中一个模块进行讲解,有兴趣的可以点击看看,也欢迎有需求的朋友试用。

    展开全文
  • IT服务管理,SOA,来看看中国IT服务管理方面的指南, 这是第二版,属于理论篇
  • 分库分表理论篇—— 以MySQL为例

    千次阅读 2020-01-19 16:52:13
    分库分表理论篇—— 以MySQL为例 文章目录分库分表理论篇—— 以MySQL为例一、背景二、如何优化三、什么是分库分表三、优势和弊端 一、背景 当今互联网大爆炸的时代,业务越来越多和大,单库单表数据超出数据库支持...
  • 博弈论中篇 研究股市 理论篇
  • 图像的特征是指图像的原始特性或属性,其中部分属于自然特征,如像素灰度、边缘和轮廓、纹理及色彩等。有些则是需要通过计算或变换才能得到的特征,如直方图、频谱和不变矩等。
  • 目标对象分类是机器视觉领域非常活跃的研究方向,在工业领域有极其广泛的应用,例如对生产线上的零件按形状、颜色等特征分拣,统计具有某种特征的零件,或通过辨别目标的类别进行质量检测等。
  • 一卡通(M1卡)破解过程记录——理论篇

    万次阅读 多人点赞 2019-07-15 15:17:33
    前些日子在研究学校的一卡通安全,在此记录一下一卡通破解的...理论篇参考了国内外的一些文献,写的比较杂乱,如有错误请指正,有条件的推荐去谷歌一些外文文献了解其原理,如《Attack.MIFARE》、《Dismantling_MIF...
  • 机器视觉系统开发过程中待处理的彩色图像就可根据需要被映射至某个色彩空间上进行描述。
  • 参考链接:http://blog.itpub.net/29119536/viewspace-1629145/ -----理论篇 参考链接:http://blog.itpub.net/29119536/viewspace-1629188/  ----实践篇
  • 理论分析EVM的原理,并从几个方面解释如何提升EVM特性。
  • VR技术原理分析,【VR原理入门理论篇】,学习研究VR技术必须要了解的理论知识。 目录 1. VR沉浸感和交互作用产生的原理: 2. 关于沉浸感和交互作用的定义 3. 如何生成符合VR要求的虚拟世界 4.最主流的VR开发...
  • 电脑游戏-结构与设计:理论篇 网络游戏开发人员必读

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 346,955
精华内容 138,782
关键字:

理论篇