对于我这样一个一直工作在.net平台上的developer来讲,Hadoop,Spark,HBase等这些大数据名词比较陌生,对于分布式计算,.net上也有类似的Parallel(我说的不是HDInsight), 这篇文章是我尝试从.net上的Parallel类库的角度去讲述什么是spark。

我们先从C#的一个烂大街的例子(不是Helloworld),统计一篇文章单词出现的频率。

下面C#代码是利用.net Parallel来写的统计单词出现频率。

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace WordCountDemo
{
using System.IO;
using System.Threading;
class Program
{
/// <summary>
/// 我们以计算一篇文章中单词的个数为例子
/// (计算文章单词个数的demo简直就是各种大数据计算的HelloWorld)。
///
/// WordCountFlow是数单词程序
/// WordCountDetail对WordCountFlow函数每一行进行拆解并做了详细解释。
/// </summary>
/// <param name="args"></param>
static void Main(string[] args)
{
string filePath = @"D:\BigDataSoftware\spark-2.1.0-bin-hadoop2.7\README.md"; WordCountFlow(filePath);
Console.WriteLine("----------------------");
WordCountDetail(filePath);
} /// <summary>
/// 数单词的程序流程
/// </summary>
/// <param name="filePath"></param>
static void WordCountFlow(string filePath)
{
File.ReadAllLines(filePath).AsParallel()
.SelectMany(t => t.Split(' '))
.Select(t => new { word = t, tag = })
.GroupBy(t => t.word).Select(t => new { word = t.Key, count = t.Select(p => p.tag).Aggregate((a, b) => a + b) })
// 如果对Aggregate函数不熟悉,上面代码等同于下行
//.GroupBy(t => t.word).Select(t => new { word = t.Key, count = t.Sum(p => p.tag) });
.ForAll(t => Console.WriteLine($"ParationId:{Thread.CurrentThread.ManagedThreadId} ({t.word}-{t.count})"));
} /// <summary>
/// 数单词程序流程的详细解释
/// </summary>
/// <param name="filePath"></param>
static void WordCountDetail(string filePath)
{
// 读取整篇文章,文章每一行将作为一个string存储到数组lines
string[] lines = File.ReadAllLines(filePath);
// AsParallel()是Parallel类库的核心方法,具体的意思是将string[] lines这个数组分割成几个分区(Partition)。
// 假设这篇文章有500行,那么这个方法会会把string[500]-lines分解成 (string[120] partitionA),
// (string[180] partitionB), (string[150] partitionC),(...) 等几个Partition
// .net runtime将当前程序的负载(主要是cpu使用情况)情况为依据的分区算法来确定到底要分成几个Partition,
// 我们可以大概认为cpu有几个逻辑核(不准确),就会被分解成几个Partition。
// 后续的计算中.net runtime将会针对每一个partition申请一个单独的线程来处理.
// 比如:partitionA由001号线程处理,partitionB由002号线程处理。。。
ParallelQuery<string> parallelLines = lines.AsParallel();
// linesA,linesB,linesC...数组中存储的每一行根据空格分割成单词,结果仍然是存放在ParallelQuery<string>这种分块的结构中
// 下面带有****的注释,如果对函数式编程没有了解,可以直接忽略。
// ****如果对函数式编程有所了解,会知道lambda天生lazy的,如果下面这行代码打个断点,当debug到这行代码的时候,
// ****鼠标移动到parallelWords上时,我们不会看到每一个单词,
// ****runtime并没有真正将每一行分解成单词,这行代码仅仅是一种计算逻辑。
ParallelQuery<string> parallelWords = parallelLines.SelectMany(t => t.Split(' '));
// 将每一个单子加上标记1,这行代码返回的类型为ParallelQuery<var>,var为runtime自动判断,此处var的类型的实际应该为
// class 匿名类型
// {
// public word {get;set;}
// public tag {get;set}
//}
var wordparis = parallelWords.Select(t => new { word = t, tag = });
// 根据单词进行分组,同一个分组中的单词个数求和,类似于如下sql select word,count(tag) from wordparis group by word
// 注意,此处同样的单词可能分布在不同的分区中,比如英语中常见的"the",可能partitionA中有3个"the",partitionB中有2个“the",
// 但是partitionA和partitionB分别被不同的线程处理,如果runtime足够聪明的话,他应该先计算partitionA的the的个数(the,3),
// 然后计算partitionB的the的个数(the,2),最后将整个partition合并并且重新分割(shuffle),在做后续的计算
// shuffle后partition的分区和之前partition里面的数据会不同。
// 此处wordcountParis的类型为
// class 匿名类型
// {
// public word {get;set;}
// public count {get;set}
//}
var wordcountParis = wordparis.GroupBy(t => t.word).Select(t => new { word = t.Key, count = t.Select(p => p.tag).Aggregate((a, b) => a + b) });
// 打印结果。由于线程执行的乱序,可以看到输出的partitionId也是乱序。
wordcountParis.ForAll(t => Console.WriteLine($"ParationId:{Thread.CurrentThread.ManagedThreadId} ({t.word}-{t.count})"));
}
}
}

  程序运行结果

  

  通过上面的c#的例子,我们看到parallel如何将一篇文章分解成多个Partition来并且在不同Partition上进行并行计算的,在计算过程中,可能需要"shuffle",需要对原来的Partition进行重新洗牌。

  我们假设,如果这个程序运行在集群上,这些Partition分布在不同的机器上,这样就可以利用多台机器的力量而非一台机器多个线程的力量去做计算了,yeah!,你猜对了,这就是spark,下面的scala的wordCountFlow函数是在spark上统计单词出现频率的函数,与c#的WordCountFlow一样,也是五行代码,并且这五行代码的逻辑也完全相同。只不过spark将数据分布在不同的机器上,并且让机器进行计算,当然,如你所想,某些情况下需要shuffle,不同机器上的数据将会被汇聚并重新分割成新的分区。虽然Spark中的partition和net parallel中的partition并不完全对应(spark中的一台机器上可能有多个paratition) ,shuffle也是spark的专用词汇,但基本的原理是类似的。

package wordCountExample

import org.apache.spark.{SparkConf, SparkContext, TaskContext}

/**
* Created by StevenChennet on 2017/3/10.
*/
object WordCount {
def main(args: Array[String]): Unit = {
// 文件路径
val filePath="D:\\BigDataSoftware\\spark-2.1.0-bin-hadoop2.7\\README.md" wordCountFlow(filePath)
}
def wordCountFlow(filePath:String ):Unit={
// sparkContext对象使用一个SparkConf对象来构造
// SparkConf主要进行一些设置,比如说local【*】表示尽量开启更多线程并行处理
// SparkContext是spark执行任务的核心对象
// 下面五行代码与C#的WordCountFlow五行代码一一对应
new SparkContext(new SparkConf().setAppName("WordCount").setMaster("local[*]")).textFile(filePath)
.flatMap(_.split(" "))
.map((_,1))
.reduceByKey(_+_)
.foreach(t=>println( s"Partition: ${ TaskContext.getPartitionId() } (${t._1}}-${t._2}})"))
}
}

  据友情提醒,上面的Scala代码的lambda太难看了,我转换一下方式

  

new SparkContext(new SparkConf().setAppName("WordCount").setMaster("local[*]")).textFile(filePath)
.flatMap(line=>line.split(" "))
.map(word=>(word,1))
.reduceByKey((a,b)=>a+b)
.foreach(t=>println( s"Partition: ${ TaskContext.getPartitionId() } (${t._1}}-${t._2}})"))
}

  

  程序运行结果

  

  在net parallel中,如果某个线程在计算过程中崩溃了,那可能导致整个程序都crash掉,如果是集群运算,因为一台宕机而让整个集群崩溃可不是一个好决策,spark可以在计算之前先对要计算的内容持久化,如果一台机器crash,可以将这台机器的计算任务拉到另外一台机器上进行重新计算。

从.net parallel角度解读spark的更多相关文章

  1. 不一样的角度 解读微信小程序

    不一样的角度 解读微信小程序 七月在夏天· 2 天前 前段时间看完了雨果奖中短篇获奖小说<北京折叠>.很有意思的是,张小龙最近也要把应用折叠到微信里,这些应用被他称为:小程序. 含着金钥匙 ...

  2. RxJava系列6(从微观角度解读RxJava源码)

    RxJava系列1(简介) RxJava系列2(基本概念及使用介绍) RxJava系列3(转换操作符) RxJava系列4(过滤操作符) RxJava系列5(组合操作符) RxJava系列6(从微观角 ...

  3. 解读Spark Streaming RDD的全生命周期

    本节主要内容: 一.DStream与RDD关系的彻底的研究 二.StreamingRDD的生成彻底研究 Spark Streaming RDD思考三个关键的问题: RDD本身是基本对象,根据一定时间定 ...

  4. 从物理执行的角度透视spark Job

    本博文主要内容: 1.再次思考pipeline 2.窄依赖物理执行内幕 3.宽依赖物理执行内幕 4.Job提交流程 一:再次思考pipeline 即使采用pipeline的方式,函数f对依赖的RDD中 ...

  5. 【Social listening实操】从社交媒体传播和文本挖掘角度解读《欢乐颂2》

    本文转自知乎 作者:苏格兰折耳喵 ----------------------------------------------------- 作为数据分析爱好者,本文作者将想从数据的角度去解读< ...

  6. Spark 概念学习系列之从物理执行的角度透视spark Job(十七)

    本博文主要内容:  1.再次思考pipeline 2.窄依赖物理执行内幕 3.宽依赖物理执行内幕 4.Job提交流程 一:再次思考pipeline 即使采用pipeline的方式,函数f对依赖的RDD ...

  7. 业余草教你解读Spark源码阅读之HistoryServer

    HistoryServer服务可以让用户通过Spark UI界面,查看历史应用(已经执行完的应用)的执行细节,比如job信息.stage信息.task信息等,该功能是基于spark eventlogs ...

  8. HBase rebalance 负载均衡源码角度解读使用姿势

    关键词:hbase rebalance 负载均衡 参考源码版本:apache-hbase-1.1.2 什么是HBase Rebalance ? 随着数据写入越来越多以及不均衡,即使一开始每个Regio ...

  9. 详细解读Spark的数据分析引擎:Spark SQL

    一.spark SQL:类似于Hive,是一种数据分析引擎 什么是spark SQL? spark SQL只能处理结构化数据 底层依赖RDD,把sql语句转换成一个个RDD,运行在不同的worker上 ...

随机推荐

  1. Confluence 6 在升级过程中查看合并日志

    为了监控升级的过程,你应该查看 application log 日志中的输出. 通常日志经常将会显示多个日志实例,这个实例是定义在日志的 INFO 级别的,通常格式如下: WikiToXhtmlMig ...

  2. 现代 PHP 新特性 —— 内置的 HTTP 服务器 (转)

    转自 https://laravelacademy.org/post/4422.html 从 PHP 5.4.0 起,PHP内置了Web服务器,这对于认为需要Apache或Nginx才能预览PHP应用 ...

  3. springBoot 随笔(一)

    服务化的世界,越来越多应用拆分为微服务,有些为了业务而拆,也有为了技术而拆,也有什么都不知道就瞎拆的,反正就是要微服务. 以下为一个认识springBoot的简单过程 1/eclipse 新建 mav ...

  4. day 11 装饰器

    1.day 10 内容复习 # 之前做得的题 以后再遇到能保证会 # 下周二考 :所有的知识 # 面试题:认真对待 # # 三元运算符 # 接收结果的变量 = 条件为真的结果 if 条件 else 条 ...

  5. FormData上传文件(input file)

    <div> <input type="file" name="FileUpload" id="FileUpload" va ...

  6. PlantUML + Chrome 联合使用

    之前都是本地下载安装一个PlantUML,安装过程有点复杂,涉及到的其他插件也有些多. 后面发现Chrome浏览器上提供了相关插件,整个过程简直太流畅了.记录下. 安装: 打开Chrome的线上应用商 ...

  7. 初识HT for web

    目前国内经济转型在潜移默化中已经发生了巨大的变化,保险,零售业,汽车等我能想到的. 只要互联网能插足的行业,都难逃一‘劫’. 刚看了一篇博客--基于 HTML5 的工业组态高炉炼铁 3D 大屏可视化 ...

  8. 初次接触Java

    今天初次接触Eclipse,学着用他来建立java工程,话不多说,来看看今天的成果! 熟悉自己手中的开发工具,热热身 刚上手别慌,有问题找度娘 刚刚拿到这个软件的安装包我是一脸懵逼的,因为是从官网下载 ...

  9. HOU 1012

    #include<iostream>using namespace std;int main(void){ int jiecheng[10]; jiecheng[0]=jiecheng[1 ...

  10. DNS区域传送、子域授权

    前言 DNS服务器搭建参考上一篇: DNS主从复制,就是将主DNS服务器的解析库复制传送至从DNS服务器,进而从服务器就可以进行正向.反向解析了.从服务器向主服务器更新查询数据,保证数据一致性,此为区 ...