一、控制流

从接触面向过程语言开始,使用控制流编程的概念已是司空见惯。

if (condition) {
// do something
} else {
// do something else
}

分支循环是最常见的控制流形式。由于控制条件的存在,总有一部分代码片段会执行,另一部分不会执行。

在控制流中,想要进行数据传递,最关键的是借助于变量保存中间状态。因此,控制流编程看起来是将数据嵌套在控制流内的编程方式。

使用变量保存程序状态有个很大的优势。通过变量缓存,可以将编程任务划分为不同的阶段,每个阶段只需要完成一部分功能子逻辑即可,这大大降低了复杂流程的思维成本。

但同时,也有一个比较大的劣势,就是在分布式处理环境下,中间状态的维护一直是一个很繁琐的问题。这从另一个方面加大了程序设计的成本。

二、数据流

而数据流编程的概念最初可以探寻到函数式编程语言,以及灵感源于此的FlumeJava类系统(如Spark、Flink等)的编程API。

rdd.map(lambda).filter(lambda).reduce(lambda);

这种类似管道流水线形式的编程接口,每次处理的数据是列表形式的(LISP)。当然,这些列表放在分布式环境下换了一个新的名词——分布式数据集(RDD/DataSet)。

数据流编程最大的特点是抽象了丰富的算子,通过UDF为算子指定用户处理逻辑。因此,数据流编程其实蕴含了控制流嵌套在数据流内的编程方式。

使用数据流编程最大的优势就是无需使用变量维护计算中间状态,另外基本的列表数据格式天然满足分布式数据存储的要求。这也是函数式语言在自我宣传时比较注重的一个优势:对并行计算支持得更好。

不过,数据流编程的方式也并不是完美。由于事先规划好的流水线结构,导致了数据处理无法自主地选择流水线分支进行处理。所以,有时候看似很简单的控制逻辑,使用数据流表达时就显得比较繁琐。

三、数据流表达的控制流

例如:下面的控制流程使用控制流编程很好表达。

if (arg > MAX) {
vertices = vertices.map(lambda);
} else {
vertices = vertices.filter(lambda);
}
return vertices;

这里的参数arg可能来源于用户输入,或者Spark/Flink driver提供的变量。这种使用driver的单机控制流全局统筹的方式好像是解决了数据流选择选择流水线管道的目的,但是实际上这是通过重新提交新任务的方式完成的。即条件为真时,才会提交true分支内的计算任务,否则提交false分支的计算任务。

如果不借助于driver,该如何表达类似的分支控制流程呢?

假定参数arg的类型也是分布式数据集类型DataSet<Integer>,它可能来源于上游流水线的中间结果,那么表达分支控制流计算可能需要如下类似方式:

// 条件数据集
DataSet<Boolean> condition = arg.map(v -> v > MAX); // 数据集 true/false 分离
DataSet<Tuple2<Vertex, Boolean>> labelVs = vertices.join(condition);
DataSet<Vertex> trueVs = labelVs.filter(v -> v.f1).map(v -> v.f0);
DataSet<Vertex> falseVs = labelVs.filter(v -> !v.f1).map(v -> v.f0); // 各自分支处理
trueVs = trueVs.map();
falseVs = falseVs.filter(); return trueVs.union(falseVs);

这里通过将参数DataSet与输入数据集vertices做join,然后分离(按条件true/false filter)出两个新的数据集trueVs和falseVs。当条件为true时,trueVs就是原始数据集vertices,而falseVs为空数据集,反之则反。然后后续只要分别对这两个数据集做相应的处理,最后把处理结果union合并起来就达到了目的。

通过这样的方式,实际上是同时执行了条件的true和false的分支逻辑,只不过任何时候总有一个分支的流水线上的数据集为空罢了。

四、思考

通过前面的讨论,可以得到一些比较明显的结论:

  • 控制流天然擅长描述控制逻辑,不过使用变量缓存中间结果不利于分布式计算抽象。
  • 数据流天然对分布式并行计算支持良好,但是在描述控制逻辑时显得十分乏力。

在计算编程语言设计领域,对控制流和数据流的讨论不绝于耳。如何让开发者更好的操纵这两类概念也在不断地探索,要不然也不会出现面向过程和函数式编程等各种编程范式。

而目前主流的计算系统,如Flink、Spark等,基本上处于使用driver的概念表达控制流,使用算子连接数据流这样的模式。不过这都是建立在driver通过全局collect操作,将数据集的数据拉取到driver基础之上的。本质上是driver根据条件分支的运行时结果,重新提交任务而已,这称不上一个精彩的设计。因为,它并没有做到让数据流具备自主选择流水线的能力。

那如何让数据流具备自主选择流水线的能力呢?说白了,自主选择流水线,本质上是拥有任务运行时修改任务执行计划的能力,也就是所谓的动态DAGRay的设计中,函数是基本的任务调度单元,而非将UDF连接起来的DAG,或许这种底层的任务抽象能力对于表达动态DAG的能力具有更大的优势。

详细了解Ray的设计,可以参考文章:高性能分布式执行框架——Ray

我的博客即将同步至腾讯云+社区,邀请大家一同入驻。

使用DataFlow表达ControlFlow的一些思考的更多相关文章

  1. 如何起草你的第一篇科研论文——应该做&避免做

    如何起草你的第一篇科研论文——应该做&避免做 导语:1.本文是由Angel Borja博士所写.本文的原文链接在这里.感谢励德爱思唯尔科技的转载,和刘成林老师的转发.2.由于我第二次翻译,囿于 ...

  2. 娓娓道来c指针 (3)指针和数组

    (3)指针和数组 在c中指针和数组似乎有着千丝万缕的关系.事实上它们不是一回事:指针是指针,数组是数组.两者不同样. 说它们有关系,只是是由于常见这种代码: int main() { int arra ...

  3. 优秀团队建设--美国式团队(ppt)

    美国式团队 一.团队精神 团队精神反映一个人的素养.一个人的能力,一个人与别人合作的精神和能力.一个团队是个有机的总体,作为个人,仅仅有全然融入到这个有机总体之中,才干最大限度地体现自己的价值. 团队 ...

  4. 毕业论文评审意见、导师意见范文、模板_Smile~风_百度空间

    body{ font-family: "Microsoft YaHei UI","Microsoft YaHei",SimSun,"Segoe UI& ...

  5. synchronized内存可见性理解

    一.背景 最近在看<Java并发编程实战>这本书,看到共享变量的可见性,其中说到"加锁的含义不仅仅局限于互斥行为,还包括内存可见性". 我对于内存可见性第一反应是vol ...

  6. Java 8 (2) 使用Lambda表达式

    什么是Lambda? 可以把Lambda表达式理解为 简洁的表示可传递的匿名函数的一种方式:它没有名称,但它有参数列表.函数主体.返回类型,可能还有一个可以抛出的异常列表. 使用Lambda可以让你更 ...

  7. 李笑来~执行力WWH

    什么是秘密 秘密是指只有极少数人知道的实用信息.这个实用信息可以为知道且懂得运用的人获得收益,这个收益可能包括钱.名声和快感. 什么是执行力 执行力=What + Why + How,即WWH 执行力 ...

  8. Redis面试热点之底层实现篇(续)

    0.题外话 接着昨天的[决战西二旗]|Redis面试热点之底层实现篇继续来了解一下ziplist压缩列表这个数据结构. 你可能会抱有疑问:我只是使用Redis的功能并且公司的运维同事都已经搭建好了平台 ...

  9. 2019HDU多校第一场1001 BLANK (DP)(HDU6578)

    2019HDU多校第一场1001 BLANK (DP) 题意:构造一个长度为n(n<=10)的序列,其中的值域为{0,1,2,3}存在m个限制条件,表示为 l r x意义为[L,R]区间里最多能 ...

随机推荐

  1. .NET之父 - Anders Hejlsberg

    简介 安德斯·海尔斯伯格(Anders Hejlsberg,1960.12~),丹麦人,Turbo Pascal编译器的主要作者,Delphi和.NET之父! 安德斯·海尔斯伯格曾在丹麦技术大学学习工 ...

  2. jdbc链接hive报错:java.lang.ClassNotFoundException: org.apache.thrift.transport.TTransport

    写了个jdbc连接hive2的demo,结果报错:java.lang.ClassNotFoundException: org.apache.thrift.transport.TTransport,实际 ...

  3. 一次从0到1的java项目实践清单

    虽说工作就是简单的事情重复做,但不是所有简单的事你都能有机会做的. 我们平日工作里,大部分时候都是在做修修补补的工作,而这也是非常重要的.做好修补工作,做好优化工作,足够让你升职加薪! 但是如果有机会 ...

  4. Java基础笔记4

    数组 有一组相同数据类型的数据. 数据类型[] 数组名称=new 数据类型[长度]; //为该数组开辟空间. 数据类型[] 数组名称={值,值}; 求数组的长度 数组名称.length; 获取数组中的 ...

  5. jQuery源码的一个坑

    纯吐槽 大半夜也真是够了,想学着jQ造个小轮子巩固下js,结果一开始就卡住了. 虽然之前也看过源码,但是主要是研究方法实现什么的,对于框架主函数和入口结构不怎么熟悉,于是想着一步一步调试看看. $(' ...

  6. 微信小程序之页面下拉刷新

    如果需要给单个页面设置下拉刷新功能,不需要写在""window"对象里面,直接在  文件名称.json 里面设置即可 { "enablePullDownRefr ...

  7. 暑假练习赛 006 E Vanya and Label(数学)

    Vanya and LabelCrawling in process... Crawling failed Time Limit:1000MS     Memory Limit:262144KB    ...

  8. gulp learning note

    为啥写这一片文章呢? 主要是为了温故而知新和分享,也是为了更加促进自己的学习! 前端自动化工具很多  有grunt  gulp  webpack 等 这次主要分享下gulp的学习经验,让自己更好的总结 ...

  9. 机器翻译评测——BLEU改进后的NIST算法

    ◆版权声明:本文出自胖喵~的博客,转载必须注明出处. 转载请注明出处:http://www.cnblogs.com/by-dream/p/7765345.html 上一节介绍了BLEU算的缺陷.NIS ...

  10. 深入分析Android动画(二)

    上回书说到Android动画的分类以及基本使用,这会书主要说Android属性动画的原理,对于View动画的原理本篇不做深入分析.对于Android动画的基础请看深入分析Android动画(一) 我们 ...