00-流式编程思想1

00-流式编程思想1

背景

  • 事件数据的产生随着时间的推移逐渐下降
  • 人们对某件事的理解往往来自基于有效论据的结论。要获得这样的结论,最有效的方法就是沿着事件发生的轨迹进行分析
  • 传统开发建立在有限的数据集基础上;那么随着数据量的增量,开发成本将会飙升
  • 通信行业的发展,促生了很多新生领域,如电商中推荐、物联网、机器学习等,新生的领域对数据的要求天然就是数据低延迟传输

目标

  • 低延迟

  • 高吞吐

  • 可容错

    系统崩溃之后,重新启动,并产出准确结果

  • 可基于事件发生时间处理

    按照正确的顺序跟踪事件,流处理的结果与事件实际发生的顺序一致

流式开发

思考

谈到流,大家很定会想到IO流;那么我们就先看下IO流;

IO流:一连串流动的字符,以先进先出方式发送信息的通道

特点:具有方向(输入流/输出流);具有顺序(字符先进先出);

随着java8的出现,引入了lambda带来的函数式编程;对多个元素进行操作,可以预先拼接一个“模型”步骤方案,然后再按照方案去执行它。

如:list.stream.filter.map.collect();

函数式编程中“Stream流”其实是一个集合元素的函数模型(处理的步骤方法),它并不是集合,也不是数据结构,其本身并不存储元素。

特点:构建执行步骤,各个算法与算法之间是无状态的

在生活中我们也会经常遇到流,网页上的点击流、汽车发送的GPS信号、移动通信基站、可穿戴设备的信号等;再具体些,如水流、公路上车流、滚动电梯、直行电梯、生产车间的工作流等等;

流数据源头广泛,但是流数据更真实的反映了我们的生活方式。

生活场景流式

工厂流水线.png

工厂的流水线是一个比较典型的流式场景;如图传送带就是数据流,传送带旁的每个工位,就相当于流式处理中的filter、map等函数

Stream流式编程

Stram流式编程又叫函数式编程,是基于数据的一种声明式编程范式

函数式编程的核心:

  • 输入:不可变的值
  • 函数:一种映射关系,将一个值映射成另外一个值
  • 输出:映射后的数据

函数式编程的特征:

  • 不可变:输入数据是不能改变的,返回的是全新的数据
  • 无状态:函数不维护任何状态

函数式编程的优势:

  • 线程安全
  • 重构代码无伤害
  • 函数执行没有顺序上的问题

函数式编程思维:

  • 函数式编程是声明式编程,因此关注的是做什么而不是怎么做

函数式编程小例(java8实现):

背景:要筛选出学生中,性别为男、年龄在10岁以上、身高大于1.3m的学生名字

public class Student {

    //姓名
    private String name;
    //年龄
    private int age;
    //性别
    private String sex;
    //身高
    private double height;

    public Student(String name, int age, String sex, double height) {
        this.name = name;
        this.age = age;
        this.sex = sex;
        this.height = height;
    }
    //忽略get/set...
 }
public static void main(String[] args) {

    List studentList = new ArrayList<>();
    studentList.add(new Student("小明", 11, "男", 15.4));
    studentList.add(new Student("小红", 10, "女", 13.0));
    studentList.add(new Student("小张", 9, "男", 13.5));
    studentList.add(new Student("小王", 11, "男", 12.9));
    studentList.add(new Student("小赵", 12, "男", 15.0));

    List names = studentList.stream()
            .filter(student -> student.getSex().equals("男"))
            .filter(student -> student.getAge() > 10)
            .filter(student -> student.getHeight() > 13.0)
            .sorted(Comparator.comparing(student -> student.getHeight()))
            .map(student -> student.getName())
            .collect(Collectors.toList());

    for (String name : names) {
        System.out.println(name);
    }

输出:

小赵
小明

例子比较简单,我们主要关注stream编程方式

概述图:

Lambda1.png

详细图:

Lambda2.png

撇开java8函数式流实现,其实我们用集合for循环也是能实现的,那么流式操作和集合操作有什么区别呢

流和集合的区别

  • 流是基于数据的,关注的是一条条数据是什么样的处理;集合是基于存储,关注的是整体
  • 流遍历一次后,返回的是一个新流,之前遍历的流已经不存在了,也就是说这个流已经被消费了,和迭代器一样,不能回头消费;集合循环完之后,集合还是存在的,可以继续重头循环
  • 从哲学的角度来看,流可以看做时间中分布的一组值。集合则是空间中(计算机内存)分布的一组值

函数式编程用到技术

  • 头等函数

  • 尾递归优化

  • pipeline(管道)

    将函数实例为一个个action,然后action放到一个数组中,再把数据传给这个action list,数据就像一个pipeline一样顺序被这些函数操作,最终得到我们希望的结果

  • 递归

  • 柯里化

  • 高阶函数

编程范式

编程范式一般可以分为三类:命令式、声明式、元编程

编程范式.png
  • 过程式编程:关注的是怎么做;核心在于模块化,实现过程使用了状态,依赖了外部变量,可读性差,维护成本高

  • 面向对象编程:关注的是抽象,提供了清晰的对象边界。封装、继承、多态的特性,降低了代码的耦合度,提升了系统的可维护性

    程序是一些列相互作用的对象

    抽象:怎么为一个模糊不清的问题找到一个恰当的描述就是抽象,抽象也是我们简化复杂问题的一种方式

    在面向对象编程里,计算程序会被设计成彼此相关的对象。对象则是类的实例,它是程序的基本单元。

  • 函数式编程:关注的是做什么;传入数据不可变性,当前函数也不依赖函数外的数据,使得函数具有自描述性,可读性高

    程序是一系列无状态的函数组合序列

    声明式编程不用告诉计算机问题领域,从而避免随之而来的副作用,而命令式编程则需要告诉计算机每一步该怎么做

对比:

面向对象 关注抽象和状态;描述对象基本特征 易于抽象和理解
代码容易重用
代码容易维护
具有可扩展性,便于阅读
并发不安全
代码易膨胀
性能较低
范式 特征 优点 缺点
过程式 关注怎么做;易于理解 性能高 依赖外部变量;
可读性低
函数式 关注做什么;不依赖当前函数外的数据 描述问题,易于理解;
无副作用(并发安全)
占用资源,性能相对较差

传统开发与流失开发区别

传统的开发会将所有数据存放在数据中心中(如一张表),然后进行加工、分析得出结果(如sql);一句话就是统一收集数据,然后进行分析。如果需要对数据中心中每月/每天数据进行分析,还是没有问题;如果需要对数据中心中每小时/每分钟/每秒进行分析,那么就有可能无法满足。

传统方式.png

既然对数据中心中的每秒数据不好处理,是否可以转变一下思想,在入数据中心中的时候,就把数据分析好放入到数据中心中呢?

流式方式.png

所以流式计算的上游,是数据流,下游是计算中心或者直接对接业务;

传统开发就是批式处理思想,那么批处理和流处理的区别呢

批处理 流处理
数据有限 数据无限
数据静态 数据动态
具有周期性 无周期性
需要时间响应 实时响应

那么流处理是不是一定优于批量处理呢,答案是否定的;如家庭用水为例,批处理相当于桶装水,流处理相当于接入水管;饮用水一般使用桶装水,生活用水一般使用自来水(接入水管);该例子主要是以使用量来选择使用场景

数据流

时间分布和数量上无解的一些列动态数据集合

流式开发特点

  • 时效性:实时(数据的价值随着时间的流逝而降低,因此必须实时计算给出实时响应)
  • 数据特征:动态、没有边界
  • 场景:实时场景;如推荐、监控等

概念相关

  • 数据流:连续数据组成的流
  • 流数据:数据流中的数据

有向无环图(DAG)

概念

有向无环图,同一个方向,但不构成闭环

DAG特点

  • 严密的拓扑性质

    具有很强的流程表达能力;按照拓扑的顺序对零散的组建进行组织执行,就可以得到正确的结果。

    计算领域,基于DAG的计算模型应用还是比较广泛的,如spark/storm/tensorflow

  • 去中心化

    每个组件拥有各自的状态;组件之间状态互不依赖

  • 具有方向

    整体具有方向;一个组件的输出可以是下个组件的输入

DAG优势

  • 任务模块化
  • 易于调整
  • 结构清晰

你可能感兴趣的:(00-流式编程思想1)