首页 文章 精选 留言 我的

精选列表

搜索[学习],共10000篇文章
优秀的个人博客,低调大师

c语言基础学习08_关于内存管理的复习

=============================================================================对于c语言来讲,内存管理是一个很重要的内容,它与指针是息息相关的,因为内存的管理都是通过指针来实现的。-----------------------------------------------------------------------------如果一个变量,它处在所有的代码块之外,那么它的生命周期就是和整个程序是一起的,程序启动的时候它就出现了,程序退出时,它才终止。如果一个变量,它处在代码块之内,那么这个代码块执行的时候它才出现,代码块执行完成后,它才消失。-----------------------------------------------------------------------------auto int i = 0;auto变量(自动变量)是在内存的栈里面,它是一个临时的变量,只有执行代码块的时候,它才会入栈,代码块执行完后,它才出栈。 static int i = 0;static变量(静态变量)是在内存的静态区里面,整个程序运行期间,该变量都存在,而且静态变量只被初始化一次。 例如: int i; for (i = 0; i < 5; i++) { static int a = 10; //定义了一个静态变量。 a++; printf("%d\n", a); } 输出结果为: 11 12 13 14 15 -------------------------------------- int i; for (i = 0; i < 5; i++) { auto int a = 10; //定义了一个自动变量。 a++; printf("%d\n", a); } 输出结果为: 11 11 11 11 11 -----------------------------------------------------------------------------在代码块之外的变量都是全局变量,那么如果加了static后,依然是全局变量,但是此时变量的作用域局限在定义这个变量的文件内部。它其实还是放在静态区的,只是外部不能访问而已。 同时函数前面也可以加一个static,如下所示: void test() //没有static,默认该函数是全局的。{ ;} static void test1() //这个函数只能在定义这个函数的文件内被调用。{ ;}注意:函数前面加static和本身的静态区没有任何关系,因为所有的函数都放在代码区,而静态区里面放的只是变量而已,不会放函数本身。 即:static放在函数的不同位置对于c语言来讲它的意义是不一样!-----------------------------------------------------------------------------extern int a; //这句话的意思是:a已经定义过了,这里只是声明。 extern void test(); //这句话的意思是:函数test已经定义过了,这里只是声明。void test(); //对于函数来说,没有extern和 有extern 对于c语言是一样的。(c语言里面一个不太好的地方) extern int a; //这句话的意思是:明确的声明了一个变量,一定不是表示定义一个变量。int a; //这句话的意思是:如果这个变量已经定义过了,这里就代表声明;如果这个变量没有定义过,这里就代表定义。 //即:不能确定它是定义还是声明。也即:出现了二义性,比较含糊。----------------------------------------------------------------------------- 在一个程序加载进内存的时候,操作系统会把不同类型的数据加载进不同的区域里面,例如: 代码区:可执行代码加载进代码区;比如:所有的函数。 静态区:所有的静态变量和全局变量都加载进静态区。实际上静态区是一个综合区,它会分很多子区,其中很多常量也是在静态区另外一个区里面放的。 常量和普通静态变量有什么区别呢? 不同点:常量也是在程序运行当中一直存在的,但是常量是只读的,普通的静态变量是可读可写的。 相同点:他们的生命周期是一样的,整个程序运行的时候他们会出现在内存里面,整个程序执行完成以后他们才从内存里面消失。 栈区:栈是一种先进后出的内存结构,所有的 自动变量、函数的形参、函数的返回值 都是由编译器自动放入内存的栈中。 当一个自动变量超出其作用域时,会自动从栈中弹出。 栈区特点是:函数调用时栈出现,函数结束时栈消失。 堆区:堆和栈一样,也是一种在程序运行过程中可以随时修改的内存区域,但没有栈那样先进后出的顺序。 堆是一个大容器,它的容量要远远大于栈,但是在c语言中,堆内存空间的申请和释放需要手动通过代码来完成。-----------------------------------------------------------------------------c、c++会用到堆和栈,但是需要去手动维护。c#、java也会用到堆和栈,但是不需要去手动维护。因而付出的代价是:不能够选择你到底使用的是堆还是栈呢。 作为一名使用者,使用c#、java语言,它们已经给你规定好了,有很多类,有很多对象,你尽管拿来用,但是它们这个类或者对象在哪里,我们不知道。我们也不需要知道,它们也不让你知道,我们就算知道也没用,因为我们也管不了,也处理不了。但是对于c语言,我们可以任意去控制这个变量是出现在栈还是堆里面。 而且c语言还比较简单,因为它所有的都是变量。而c++和java还有对象,在c++里面可以指定你的对象在栈里面还是在堆里面,即可以选择效率最高的方法来使用对象,而在java里面所有的对象都是出现在堆里面的。 这就是c和c++语言的魅力所在,以及它们做操作系统的原因之一,因为它们可以自由的控制内存中的每一个字节。-----------------------------------------------------------------------------用递归代码实现栈的先进后出效果(递归的过程是典型的先入栈后出栈过程) linux下示例代码如下: 1 #include <stdio.h> 2 3 //用递归代码实现栈的先进后出效果(递归的过程是典型的先入栈后出栈过程) 4 5 void test(int n) 6 { 7 printf("%p, n = %d\n", &n, n); //把代码放到递归的前面,叫做先序递归。 8 if (n < 3) 9 { 10 test(n + 1); 11 } 12 printf("%p, n = %d\n", &n, n); //把代码放到递归的前面,叫做先序递归。 13 } 14 15 int main() 16 { 17 test(0); 18 19 return 0; 20 } 21 输出结果为: 22 0x7ffe5e720b0c, n = 0 第一个入栈 23 0x7ffe5e720aec, n = 1 24 0x7ffe5e720acc, n = 2 25 0x7ffe5e720aac, n = 3 26 0x7ffe5e720aac, n = 3 27 0x7ffe5e720acc, n = 2 28 0x7ffe5e720aec, n = 1 29 0x7ffe5e720b0c, n = 0 最后一个出栈 test(0) { printf("%p, n = %d\n", &n, n); //0x7ffe5e720b0c, n = 0 test(1) { printf("%p, n = %d\n", &n, n); //0x7ffe5e720aec, n = 1 test(2) { printf("%p, n = %d\n", &n, n); //0x7ffe5e720acc, n = 2 test(3) { printf("%p, n = %d\n", &n, n); //0x7ffe5e720aac, n = 3 4 < 3;不符合if的判断条件,推迟if判断语句,则继续执行剩余代码: printf("%p, n = %d\n", &n, n); //0x7ffe5e720aac, n = 3 } printf("%p, n = %d\n", &n, n); //0x7ffe5e720acc, n = 2 } printf("%p, n = %d\n", &n, n); //0x7ffe5e720aec, n = 1 } printf("%p, n = %d\n", &n, n); //0x7ffe5e720b0c, n = 0 } -----------------------------------------------------------------------------如果程序中申请了堆内存,但忘记了free,如果程序退出的时候操作系统会统一进行回收;但如果程序一直不退出,那么这块内存就会一直被占用,有时更可气的是,你不但不退出程序,而且还在不停的申请新的内存,也不free,最后操作系统的内存被你“吃光了”,导致内存泄漏!-----------------------------------------------------------------------------例如:int *p = malloc(200);p = realloc(p, 400); //在p的基础上,将堆内存扩展到400个字节。p = realloc(p, 100); //在p的基础上,将堆内存缩小到100个字节。int *p1 = realloc(NULL,100); //如果realloc的第一个参数是NULL,那么realloc的作用和malloc是一样的。----------------------------------------------------------------------------- 1、 1 int *test() //错误的代码 2 { 3 int i = 0; //i在栈里面,生命周期就是其所处的大括号。 4 return &i; 5 } 6 7 int main() 8 { 9 int *p = test(); //p指向了一个无效的地址。 10 *p = 10; 11 return 0; 12 } 13 -------------------------------------- 14 int *test() //正确的代码 15 { 16 int *i = malloc(sizeof(int)); //i在堆里面。生命周期很长。主动调用free,堆空间释放或者进程结束,操作系统进行内存空间回收。 17 return i; 18 } 19 20 int main() 21 { 22 int *p = test(); 23 *p = 10; 24 free(p); 25 return 0; 26 } 2、 1 void test(char *i) //错误的代码 2 { 3 i = malloc(sizeof(char) * 100); //i在栈里,指向了堆的地址。 4 } 5 6 int main() 7 { 8 char *p = NULL; 9 test(p); //实参的值可以传递给形参,形参的值发生改变,实参的值不会有影响。 10 strcpy(p, "hello"); 11 free(p); 12 return 0; 13 } 14 -------------------------------------- 15 void test(char **i) //正确代码,通过二级指针解决上面这个问题。 16 { 17 *i = malloc(sizeof(char) * 100); 18 19 } 20 21 int main() 22 { 23 char *p = NULL; 24 test(&p); 25 strcpy(p, "hello"); 26 free(p); 27 return 0; 28 } 29 小结:若想通过函数形参给实参分配内存,往往是通过二级指针来实现的。这是在c语言里面常用的技巧。 30 -------------------------------------- 31 char *test() //正确的代码 32 { 33 char *i = malloc(sizeof(char) * 100); //i在堆里面。 34 return i; 35 } 36 37 int main() 38 { 39 char *p = test(); 40 strcpy(p, "hello"); 41 free(p); 42 return 0; 43 } 3、 1 void test(char *i) //错误的代码 2 { 3 strcpy(i, "hello"); 4 } 5 6 int main() 7 { 8 test("hello"); //在栈里面:i = "hello"是常量。常量不可变。 9 return 0; 10 } 11 -------------------------------------- 12 const char *test() //正确的代码 函数的返回值是一个指向常量的指针。即该指针可以指向任何常量的地址。 13 { 14 return "hello"; //"hello"是常量。而且是字符串。所以它是const char *类型的。 15 } 16 17 int main() 18 { 19 const char *s = test(); 20 printf("%s\n", s); 21 return 0; 22 } 4、 1 char *test() //错误的代码 函数的返回值是指针变量。 2 { 3 return "hello"; //"hello"是常量。实际返回值是一个常量。 4 } 5 6 int main() 7 { 8 char *s = test(); 9 strcpy(s,"aabbcc"); 10 printf("%s\n", s); 11 return 0; 12 } 13 -------------------------------------- 14 const char *test() //错误的代码 15 { 16 const char a[] = "hello"; //数组a是自动变量,在栈里面。"hello"是常量,在静态区里面。从语法的角度const作用是:不能这样(a[0] = 'a';)去修改它的值。只读。 17 return a; 18 } 19 20 int main() 21 { 22 const char *s = test(); 23 printf("%s\n", s); 24 return 0; 25 } 26 -------------------------------------- 27 const char *test() //正确的代码 28 { 29 static char a[] = "hello"; //此时数组a在静态区里面。 30 return a; 31 } 32 33 int main() 34 { 35 const char *s = test(); //从语法的角度const作用是:不能这样(s[0] = 'a';)去修改它的值。只读。 36 printf("%s\n", s); 37 return 0; 38 } ============================================================================= 我的GitHub地址: https://github.com/heizemingjun 我的博客园地址: http://www.cnblogs.com/chenmingjun 我的蚂蚁笔记博客地址: http://blog.leanote.com/chenmingjun Copyright ©2018 黑泽明军 【转载文章务必保留出处和署名,谢谢!】

优秀的个人博客,低调大师

Linux_学习_02_ 重启tomcat与查看tomcat日志

一、重启tomcat服务器 cd /home/ehlhec/tomcat_dingtalk/bin ./shutdown.sh ps -ef|grep java ./startup.sh (1) 进入linux系统下tomcat的bin目录, cd /home/ehlhec/tomcat_dingtalk/bin (2)关闭一下tomcat服务,特别是已经启动的情况下,只不过有些异常 ./shutdown.sh (3)检查一下tomcat是否确实已经关闭 ps -ef|grep java 假如出现以下类似的提示,表示tomcat已经关闭 root 30248 30113 0 10:00 pts/0 00:00:00 grep java 若是没有关闭,则可以使用kill命令,直接结束掉tomcat进程 kill -9 进程名 (4)最后重新启动tomcat ./startup.sh 二、查看日志 logs: cd /home/ehlhec/tomcat_dingtalk/logs tail -f catalina.out wfl7010

优秀的个人博客,低调大师

《从零开始学Swift》学习笔记(Day 44)——重写属性

重写实例属性 我们可以在子类中重写从父类继承来的属性,属性有实例属性和静态属性之分,他们在具体实现也是不同的。 实例属性的重写一方面可以重写getter和setter访问器,另一方面可以重写属性观察者。 计算静态属性需要使用getter和setter访问器,而存储属性不需要。子类在继承父类后,也可以通过getter和setter访问器重写父类的存储属性和计算属性。 下面看一个示例: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 class Person{ varname:String //存储属性 varage:Int //存储属性 funcdescription()->String{ return "\(name)年龄是:\(age)" } init(name:String,age:Int){ self.name=name self.age=age } } class Student:Person{ varschool:String overridevarage:Int{ //重写属性前面要添加override关键字 get{ return super .age } set{ super .age=newValue< 8 ? 8 :newValue } } convenienceinit(){ self.init(name: "Tony" ,age: 18 ,school: "清华大学" ) } init(name:String,age:Int,school:String){ self.school=school super .init(name:name,age:age) } } letstudent1=Student() print( "学生年龄:\(student1.age)" ) student1.age= 6 print( "学生年龄:\(student1.age)" ) 从属性重写可见,子类本身并不存储数据,数据是存储在父类的存储属性中的。 以上示例是重写属性getter和setter访问器,我们还可以重写属性观察者,代码如下: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 class Person{ varname:String varage:Int funcdescription()->String{ return "\(name)年龄是:\(age)" } init(name:String,age:Int){ self.name=name self.age=age } } class Student:Person{ varschool:String overridevarage:Int{ //重写了age属性观察者 willSet{ //如果只关注修改之前的调用,可以只重写willSet观察者 print( "学生年龄新值:\(newValue)" ) } didSet{ //如果只关注修改之后的调用,可以只重写didSet观察者 print( "学生年龄旧值:\(oldValue)" ) } } convenienceinit(){ self.init(name: "Tony" ,age: 18 ,school: "清华大学" ) } init(name:String,age:Int,school:String){ self.school=school super .init(name:name,age:age) } } letstudent1=Student() print( "学生年龄:\(student1.age)" ) Student1.age= 6 print( "学生年龄:\(student1.age)" ) 代码Student1.age = 6修改了age属性,修改前后的输出结果如下: 学生年龄新值:6 学生年龄旧值:18 重写静态属性 在类中静态属性定义使用class或static关键字,但是使用哪一个要看子类中是否重写该属性。class修饰的属性可以被重写,static关键字就不能被重写。 示例代码如下: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 class Account{ varamount:Double= 0.0 //账户金额 varowner:String= "" //账户名 varinterestRate:Double= 0.0668 //利率 //class不能换成static class varstaticProp:Double{ //静态属性staticProp return 0.0668 *1_000_000 } varinstanceProp:Double{ return self.interestRate*self.amount } } class TermAccount:Account{ //class换成static override class varstaticProp:Double{ //重写静态属性staticProp return 0.0700 *1_000_000 } } //访问静态属性 print(Account.staticProp) print(TermAccount.staticProp) 由于要被重写所以代码class var staticProp: Double中的class不能换成static。代码overrideclass var staticProp: Double中的静态属性staticProp可以使用class或static,除非在TermAccount的子类中重写属性staticProp。 本文转自 tony关东升 51CTO博客,原文链接:http://blog.51cto.com/tonyguan/1747501,如需转载请自行联系原作者

优秀的个人博客,低调大师

Storm概念学习系列之什么是实时流计算?

什么是实时流计算? 1、实时流计算背景 2、实时计算应用场景 3、实时计算处理流程 4、实时计算框架 什么是实时流计算? 所谓实时流计算,就是近几年由于数据得到广泛应用之后,在数据持久性建模不满足现状的情况下,急需数据流的瞬时建模或者计算处理。这种实时计算的应用实例有金融服务、网络监控、电信数据管理、 Web 应用、生产制造、传感检测,等等。在这种数据流模型中,单独的数据单元可能是相关的元组(Tuple),如网络测量、呼叫记录、网页访问等产生的数据。但是,这些数据以大量、快速、时变(可能是不可预知)的数据流持续到达,由此产生了一些基础性的新的研究问题——实时计算。实时计算的一个重要方向就是实时流计算。 实时流计算背景 数据的价值随着时间的流逝而降低,所以事件出现后必须尽快对它们进行处理,最好事件出现时便立刻对其进行处理,发生一个事件进行一次处理,而不是缓存起来成一批处理。例如商用搜索引擎,像 Google、 Bing 和 Yahoo! 等,通常在用户查询响应中提供结构化的Web 结果,同时也插入基于流量的点击付费模式的文本广告。为了在页面上的最佳位置展现最相关的广告,通过一些算法来动态估算给定上下文中一个广告被点击的可能性。上下文可能包括用户偏好、地理位置、历史查询、历史点击等信息。一个主搜索引擎可能每秒钟处理成千上万次查询,每个页面都可能会包含多个广告。为了及时处理用户反馈,需要一个低延迟、可扩展、高可靠的处理引擎。 对于这些实时性要求很高的应用,若把持续到达的数据简单地放到传统数据库管理系统DBMS)中,并在其中进行操作,是不切实际的。传统的 DBMS 并不是为快速连续地存放单的数据单元而设计的,而且也不支持“持续处理”,而“持续处理”是数据流应用的典型特征。另外,现在人们都认识到,“近似性”和“自适应性”是对数据流进行快速查询和其处理(如数据分析和数据采集)的关键要素,而传统 DBMS 的主要目标恰恰与之相反:通稳定的查询设计,得到精确的答案。 另外一些方案是采用 MapReduce 来处理实时数据流。但是,尽管 MapReduce 做了实时性改进,也很难稳定地满足应用需求。这是因为 Hadoop MapReduce 框架为批处理做了高度优化,典型的是通过调度批量任务来操作静态数据,任务不是常驻服务,数据也不是实时流入;而数据流计算的典型范式之一是不确定数据速率的事件流流入系统,系统处理能力必须与事件流量匹配。 实时计算应用 互联网领域的实时流计算一般都是针对海量数据进行的,除了非实时计算的需求(如计算结果准确)以外,实时计算最重要的一个需求是能够实时响应计算结果,一般要求为秒级。个人理解,互联网行业的实时计算可以分为以下两种应用场景。 1)数据源是实时的、不间断的,要求对用户的响应时间也是实时的。主要用于互联网流式数据处理。所谓流式数据,是指将数据看作数据流的形式来处理。数据流则是在时间分布和数量上无限的一系列数据记录的集合体;数据记录是数据流的最小组成单元。例如,对于大型网站,活跃的流式数据非常常见,这些数据包括网站的访问 PV/UV、用户访问的内容、搜索的内容等。实时的数据计算和分析可以动态实时地刷新用户访问数据,展示网站实时流量的变化情况,分析每天各小时的流量和用户分布情况,这对于大型网站来说具有重要的实际意义。 2)数据量大且无法或没必要预算,但要求对用户的响应时间是实时的。主要用于特定场合下的数据分析处理。当数据量很大,同时发现无法穷举所有可能条件的查询组合或者大量穷举出来的条件组合无用时,实时计算就可以发挥作用,将计算过程推迟到查询阶段进行,但需要为用户提供实时响应。 实时计算处理流程 互联网上海量数据(一般为日志流)的实时计算过程可以划分为 3 个阶段:数据的产生与收集阶段、传输与分析处理阶段、存储对对外提供服务阶段,如图 1-1 所示。下面分别进行简单介绍。 图 1 实时计算处理流程 (1)数据实时采集 需求:功能上保证可以完整地收集到所有日志数据,为实时应用提供实时数据;响应时间上要保证实时性、低延迟(在 1s 左右);配置简单,部署容易;系统稳定可靠等。 目前,互联网企业的海量数据采集工具有 Facebook 开源的 Scribe、 LinkedIn 开源的Kafka、 Cloudera 开源的 Flume,淘宝开源的 TimeTunnel、 Hadoop 的 Chukwa等,它们均可以满足每秒数百 MB 的日志数据采集和传输需求。 (2)数据实时计算 传统的数据操作,首先将数据采集并存储在 DBMS 中,然后通过查询和 DBMS 进行交互,得到用户想要的答案。在整个过程中,用户是主动的,而 DBMS 系统是被动的,过程操作如图 1-2 所示。 图 2 传统的数据操作流程 但是,对于现在大量存在的实时数据,如股票交易的数据,这类数据实时性强,数据量大,没有止境,传统的架构并不合适。流计算就是专门针对这种数据类型准备的。在流数据不断变化的运动过程中实时地进行分析,捕捉到可能对用户有用的信息,并把结果发送出去。在整个过程中,数据分析处理系统是主动的,而用户却处于被动接收的状态,处理流程如图 3 所示。 图 3 流计算处理过程 需求:适应流式数据、不间断查询;系统稳定可靠、可扩展性好、可维护性好等。有关计算的一些注意点:分布式计算、并行计算(节点间的并行、节点内的并行)、热点数据的缓存策略、服务端计算。 (3)实时查询服务 全内存:直接提供数据读取服务,定期转存到磁盘或数据库进行持久化。 半内存:使用 Redis、 Memcache、 MongoDB、 BerkeleyDB 等内存数据库提供数据实时查询服务,由这些系统进行持久化操作。 全磁盘:使用 HBase 等以分布式文件系统(HDFS)为基础的 NoSQL 数据库,对于KeyValue 内存引擎,关键是设计好 Key 的分布。 实时计算框架 最近这几年随着实时计算的流行,相继出现了以下实时计算的框架。 1、 IBM 的 StreamBase StreamBase 是 IBM 开发的一款商业流式计算系统,在金融行业和政府部门使用,其本身是商业应用软件,但提供了开发版。相对于付费使用的企业版,开发版的功能更少,但这并不妨碍我们从外部使用 API 接口来对 StreamBase 本身进行分析。 StreamBase 使用 Java 开发, IDE 是基于 Eclipse 进行二次开发,功能非常强大。 StreamBase也提供了相当多的 Operator、 Functor 以及其他组件来帮助构建应用程序。用户只需要通过 IDE拖拉控件,然后关联,设置好传输的 Schema 并且设置控件计算过程,就可以编译出一个高效处理的流式应用程序。同时, StreamBase 还提供了类 SQL 来描述计算过程。 StreamBase 的架构如图 1-4 所示。 StreamBase Server 是节点上启动的管理进程,它负责管理节点上 Container 的实例,每个 Container 通 过 Adapter 获 得 输 入, 交 给 应 用 逻 辑 计 算, 然 后 通 过 Adapter 输 出。 各 个Container 相互连接,形成一个计算流图。 图4 StreamBase 架构图 Adapter 负责与异构输入或输出交互,源或目的地可能包括 CSV 文件、 JDBC、 JMS、Simulation( StreamBase 提供的流产生模拟器)或用户定制。 每个 StreamBase Server 上面都会有一个 System Container,主要是产生系统监控信息的流式数据。 HA Container 用于容错恢复,可以看出它实际包含两个部分: Heartbeat 和 HA Events,其中 Heartbeat 也是 Tuple 在 Container 之间传输。在 HA 方案下, HA Container 监控 PrimaryServer 的活动情况,然后将这些信息转换成为 HA Events 交给 StreamBase Monitor 来处理。 Monitor 就是从 System Container 和 HA Container 中获取数据并进行处理。 StreamBase认为 HA 问题应该通过 CEP 方式处理,也就是说出现问题的部件肯定会反映在 SystemContainer 和 HA Container 的输出流上面, Monitor 如果通过复杂事件处理这些 Tuples 就能够检测到机器故障等问题,并做出相应处理。 2、Yahoo 的 S42 Yahoo! S4(Simple Scalable Streaming System)是一个通用的、分布式的、可扩展的、分区容错的、可插拔的流式系统 。基于 S4 框架,开发者可以容易地开发面向持续流数据处理的应用。 S4 的最新版本是 v0.6.0,是 Apache 孵化项目,其设计特点有以下几个方面。 Actor 计算模型:为了能在普通机型构成的集群上进行分布式处理,并且在集群内部不使用共享内存, S4 架构采用了 Actor 模式,这种模式提供了封装和地址透明语义,因此在允许应用大规模并发的同时,提供了简单的编程接口。 S4 系统通过处理单元(Processing Elements, PEs)进行计算,消息在处理单元间以数据事件的形式传送,PE 消费事件,发出一个或多个可能被其他 PE 处理的事件,或者直接发布结果。每个PE 的状态对于其他 PE 不可见, PE 之间唯一的交互模式就是发出事件和消费事件。 对等集群架构: S4 采用对等架构,集群中的所有处理节点都是等同的,没有中心控制节点,这使得集群的扩展性很好,处理节点的总数理论上无上限;同时, S4 没有单点容错的问题。 可插拔体系架构: S4 系统使用 Java 语言开发,采用了极富层次的模块化编程,每个通用功能点都尽量抽象出来作为通用模块,而且尽可能地让各模块实现可定制化。 支持部分容错:基于 ZooKeeper 服务的集群管理层会自动路由事件从失效节点到其他节点。除非显式保存到持久性存储,否则节点故障时,节点上处理事件的状态会丢失。 S4 的重要应用场景是预估点击通过率(CTR)。 CTR 是广告点击数除以展现数得到的比率,拥有足够历史的展现和点击数据后, CTR是用户点击广告可能性的一个很好的估算,精确的来源点击对于个性化和搜索排名来说都价值无限。据 S4 的开发者称,在线流量上的实验显示基于S4系统的新CTR计算框架可以在不影响收入的前提下将 CTR 值提高 3%,这主要是通过快速检测低质量的广告并把它们过滤出去而获得的收益。 S4 系统提供的低延迟处理能够使得商务广告部门获益,但是潜在的风险也不能忽视,那就是事件流的速率快到一定程度后,S4可能无法处理, 会导致事件的丢失, 如图4所示。 图 5 S4 在流量压力测试下的事件丢失情况 3、Twitter 的 Storm Twitter 的 Storm : Storm 是一个分布式的、容错的实时计算系统。 Storm 的用途:可用于处理消息和更新数据库(流处理),在数据流上进行持续查询,以流的形式返回结果到客户端(持续计算),并行化一个类似实时查询的热点查询(分布式的 RPC)。 Storm 为分布式实时计算提供了一组通用原语,可被用于“流处理”中,实时处理消息并更新数据库。这是管理队列及工作者集群的另一种方式。 Storm 也可用于“连续计算” ( continuous computation),对数据流做连续查询,在计算时将结果以流的形式输出给用户。它还用于“分布式 RPC”,以并行的方式运行昂贵的运算。 Storm 的主要特点如下: 简单的编程模型。类似于 MapReduce 降低了并行批处理复杂性, Storm 降低了进行实时处理的复杂性。 可以使用各种编程语言。可以在 Storm 上使用各种编程语言。默认支持 Clojure、Java、 Ruby 和 Python。要增加对其他语言的支持,只需实现一个简单的 Storm 通信协议即可。 容错性。 Storm 会管理工作进程和节点的故障。 水平扩展。计算是在多个线程、进程和服务器之间并行进行的。 可靠的消息处理。 Storm 保证每个消息至少能得到一次完整处理。当任务失败时,它会负责从消息源重试消息。 快速。系统的设计保证了消息能得到快速的处理,使用 ZeroMQ 作为其底层消息队列。 本地模式。 Storm 有一个“本地模式”,可以在处理过程中完全模拟 Storm 集群。这可以使用户快速进行开发和单元测试。 4、Twitter 的 Rainbird Rainbird 是一款分布式实时统计系统,可以用于实时数据的统计。 1)统计网站中每一个页面,域名的点击次数。 2)内部系统的运行监控(统计被监控服务器的运行状态)。 3)记录最大值和最小值。 Rainbird 构建在 Cassandra 上,使用 Scala 编写,依赖于 ZooKeeper、 Scribe 和 Thrift。每秒可以写入 10 万个事件,而且都带有层次结构,或者进行各种查询,延迟小于 100ms。目前 Twitter 已经在 Promoted Tweets、微博中的链接、短地址、每个用户的微博交互等生产环境使用了 Rainbird。其主要组件的功能如下。ZooKeeper:是 Hadoop 子项目中的一款分布式协调系统,用于控制分布式系统中各个组件的一致性。Cassandra:是 NoSQL 中一款非常出色的产品,集合了 Dynamo 和 BigTable 特性的分布式存储系统,用于存储需要统计的数据,并提供客户端查询统计数据(需要使用分布式 Counter 补丁 CASSANDRA-1072)。Scribe:是 Facebook 开源的一款分布式日志收集系统,用于在系统中将各个需要统计的数据源收集到 Cassandra 中。Thrift:是 Facebook 开源的一款跨语言 C/S 网络通信框架,开发人员基于该框架可以轻松地开发 C/S 应用。 5、Facebook 的 Puma Puma 是 Facebook 的数据流处理系统,早期的处理系统如图 1-6 所示,即二代 Puma。PTail 将数据以流的方式传递给 Puma 2, Puma 2 每秒需要处理百万级的消息,处理多为Aggregation 方式的操作,遵循时间序列,涉及的复杂 Aggregation 操作诸如独立访次、最频繁事件,等等。 图 6 Puma 2 系统数据处理通路 对于每条消息, Puma 2 发送“Increment”操作到 HBase。考虑到自动负载均衡、自动容错和写入吞吐等因素, Puma 选择 HBase 而不是 MySQL 作为其存储引擎。 Puma 2的服务器都是对等的,即同时可能有多个 Puma 2 服务器向 HBase 中修改同一行数据。因此,Facebook 为 HBase 增加了新的功能,支持一条 Increment 操作修改同行数据的多列。 Puma 2的架构非常简单并且易于维护,其涉及的状态仅仅是 PTail 的 Checkpoint,即上游数据位置周期性地存储在 HBase中。由于是对称结构,集群扩容和机器故障的处理都非常方便。不过, Puma 2的缺点也很突出,首先,HBase的Increment操作是非常昂贵的,因为它涉及读和写,而HBase的随机读效率比较差;另外,复杂 Aggregation 操作也不好支持,需要在 HBase上写很多用户代码;再者,Puma 2在故障时会产生少量重复数据,因为 HBase的 Increment 和 PTail 的 Checkpoint 并不是一个原子操作。 但值得一提的是, Puma 并没有开源出来,用户可以了解和借鉴其实现原理。 6、阿里的 JStorm JStorm 是一个 Alibaba 开源的分布式实时计算引擎,可以认为是 Twitter Storm 的 Java版本,用户按照指定的接口实现一个任务,然后将这个任务递交给 JStorm 系统, JStorm 会启动后台服务进程 7×24 小时运行,一旦某个 Worker 发生故障,调度器立即分配一个新的Worker 替换这个失效的 Worker。 JStorm 处理数据的方式是基于消息的流水线处理,因此特别适合无状态计算,也就是计算单元依赖的数据全部可以在接受的消息中找到,并且最好一个数据流不依赖另外一个数据流。因此, JStorm 适用于下面的场景: 日志分析。从日志中分析出特定的数据,并将结果存入外部存储器,如数据库。 管道系统。将数据从一个系统传输到另外一个系统,如将数据库同步到 Hadoop。 消息转化器。将接收到的消息按照某种格式转化,存储到另外一个系统,如消息中间件中。 统计分析器。从日志或消息中提炼出某个字段,然后进行 COUNT 或 SUM 计算,最后将统计值存入外部存储器。 但是, JStorm 的活跃度并不高,截至本章书写时,整个 JStorm 项目共提交过 36 次,并且只有 1 个 Committer,相比 Twitter Storm,不管是活跃度,还是认可度都还不是一个数量级的产品。 7、其他实时计算系统 (1) HStreaming HStreaming 是建立在 Hadoop 上的可扩展的、可持续的数据分析系统。它可以分析、可视化并处理大量连续数据,如一个金融交易系统实时展示数据图。 HStreaming 由 Jana Uhlig与 Volkmar Uhlig 联合创立,该公司没有提供相关产品的开源版本,从官网信息来看,只提供相关的解决方案。 HStreaming 公司尝试为 Hadoop 环境添加一个实时的组件,当数据提交到系统,在存储到磁盘之前会进行数据处理,类似开源的 Storm 和 Kafka。目前 HStreaming 已经建立了一个完整的系统,该系统能够利用实时的引擎来处理视频、服务器、传感器以及其他机器上生成的数据流,而且完全兼容 Hadoop 作为一个归档和批量处理系统。 (2) Esper Esper 是 EsperTech 公司使用 Java 开发的事件流处理(Event Stream Processing, ESP)和复杂事件处理(Complex Event Processing, CEP)引擎。 CEP 是一种实时事件处理并从大量事件数据流中挖掘复杂模式的技术。 ESP 是一种从大量事件数据流中过滤、分析有意义的事件,并能够实时取得这些有意义的信息的技术。该引擎可应用于网络入侵探测、 SLA 监测、RFID 读取、航空运输调控、金融(风险管理、欺诈探测)等领域。 Esper 可以用在股票系统、风险监控系统等实时性要求比较高的系统中。 (3) Borealis Borealis 是由 Brandeis University、 Brown University 和 MIT 合作开发的一个分布式流式系统,由之前的流式系统 Aurora、 Medusa 演化而来,是学术研究的一个产品, 2008 年已经停止维护。 Borealis 具有丰富的论文、完整的用户 / 开发者文档,系统是用 C++ 实现的,运行于x86-based Linux 平台。系统是开源的,同时使用了较多的第三方开源组件,包括用于查询语言翻译的 ANTLR、 C++ 的网络编程框架库 NMSTL 等。 Borealis 系统的流式模型和其他流式系统基本一致:接受多元的数据流和输出流,为了容错,采用确定性计算,对于容错性要求高的系统,会对输入流使用算子进行定序。 8、框架对比 实时数据流计算是近年来分布式、并行计算领域研究和实践的重点,无论是工业界,还是学术界,都诞生了多个具有代表性的数据流计算系统,用于解决实际生产问题和进行学术研究。不同的系统满足不同应用的需求,系统并无好坏之分,关键在于服务的对象是谁。图 1-7 从开发语言、高可用机制、支持精确恢复、主从架构、资源利用率、恢复时间、支持状态持久化及支持去重等几个方面比较了典型的 3 个数据流计算系统 Puma、 Storm 和 S4。因为 StreamBase 是厂商发行商用版本, HStreaming 只提供解决方案,而 JStorm 和 Storm 非常相似,所以这几种产品并没有罗列在图 7 中。 图7 Puma、 Storm 和 S4 三种数据流计算系统对比 可以看到,为了高效开发,两个系统使用 Java,另一种系统使用函数式编程语言Clojure ;高可用方案,有两个系统使用 Primary Standby 方式,系统恢复时间可控,但系统复杂度增加,资源使用率也较低,因为需要一些机器来当备机;而 Storm 选择了更简单可行的上游回放方式, 资源使用率高,就是恢复时间可能稍长些; Puma 和 S4 都支持状态持久化,但 S4 目前不支持数据去重,未来可能会实现;三个系统都做不到精确恢复,即恢复后的执行结果和无故障发生时保持一致,因为即使是 Primary Standby 方式,也只是定期Checkpoint,并没有跟踪每条消息的执行。商用的 StreamBase 支持精确恢复,这主要应用于金融领域。 本文转自大数据躺过的坑博客园博客,原文链接:http://www.cnblogs.com/zlslch/p/5989237.html,如需转载请自行联系原作者

优秀的个人博客,低调大师

《从零开始学Swift》学习笔记(Day 59)——代码排版

代码排版包括:空行、空格、断行和缩进等内容。代码排版内容比较多工作量很多,但是非常重要。 空行 空行将逻辑相关的代码段分隔开,以提高可读性。下列情况应该总是添加空行: 类型声明之前。 import语句前后。 两个方法或函数之间。 块注释或单行注释之前。 方法或函数内的两个逻辑段之间,用以提高可读性。 一个源文件的两个片段之间。 空格 在代码中有些位置是需要有空格的,这个工作量也是很大的。下列是使用空格的规范: 1.赋值符号“=”前后有一个空格。var或let与标识符之间有一个空格。所有的二元运算符,应该使用空格将之与操作数分开。一元操作符和操作数之间不因该加空格,如:++、--等。示例如下。 1 2 3 vara= 10 varc= 10 a+=c+d 2.小左括号“(”之后,小右括号“)”之前不要有空格。示例如下。 1 a=(a+b)/(c*d) 3.大左括号“{”之前有一个空格。示例如下。 1 2 3 while a==d{ n++ } 4.在方法或函数参数之前间有一个空格,参数冒号与数据类型之间有一个空格。 推荐使用: 1 2 3 4 functableView(tableView:UITableView,didSelectRowAtIndexPathindexPath:NSIndexPath){ ... } 不推荐使用: 1 2 3 functableView(tableView:UITableView,didSelectRowAtIndexPathindexPath:NSIndexPath){ ... } 断行 一行代码的长度尽量避免超过80个字符,为了便于查看是否一行代码超出80个字符,很多IDE开发工具都可以在编辑窗口设置显示80行竖线。在Xcode中设置过程是打开菜单Xcode→Preferences,选择Text Editing标签,选中Show→Page guideat column。 由于有的代码比较长需要断行,可以依据如下一般规范断开: 在一个逗号后面断开。 在一个操作符前面断开,要选择较高级别运算符断开,而非较低级别运算符断开。 新的一行应该与上一行缩进两个级别(8个空格) 缩进 4个空格常被作为缩进排版的一个单位,在开发时候使用制表符进行缩进,虽然默认情况下一个制表符等于8个空格,但是在不同的IDE工具中可能设置的一个制表符与空格对应个数会有所不同。在Xcode中默认是一个制表符对应4个空格,我们可以在Xcode中打开菜单Xcode→Preferences,选择Text Editing→Indentation标签,可以在Tab width中进行设置。 缩进可以依据如下一般规范: 在函数、方法、闭包、控制语句、计算属性等包含大括号“{}”代码块中,代码块中的内容与首行缩进一个级(4个空格)。 如果是if语句中条件表达式的断行,那么新的一行应该与上一行缩进两个级别(8个空格),再往后的断行要与第一次的断行对齐。 本文转自 tony关东升 51CTO博客,原文链接:http://blog.51cto.com/tonyguan/1748346,如需转载请自行联系原作者

优秀的个人博客,低调大师

【Android开发学习笔记之一】5大布局方式详解

Android中常用的5大布局方式有以下几种: 线性布局(LinearLayout):按照垂直或者水平方向布局的组件。 帧布局(FrameLayout):组件从屏幕左上方布局组件。 表格布局(TableLayout):按照行列方式布局组件。 相对布局(RelativeLayout):相对其它组件的布局方式。 绝对布局(AbsoluteLayout):按照绝对坐标来布局组件。 1. 线性布局 线性布局是Android开发中最常见的一种布局方式,它是按照垂直或者水平方向来布局,通过“android:orientation”属性可以设置线性布局的方向。属性值有垂直(vertical)和水平(horizontal)两种。 常用的属性: android:orientation:可以设置布局的方向 android:gravity:用来控制组件的对齐方式 layout_weight:控制各个组件在布局中的相对大小 第一个实例 ①效果图: ②核心代码如下: main.xml 1 <?xml version="1.0" encoding="utf-8"?> 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 android:orientation="vertical" 4 android:layout_width="fill_parent" 5 android:layout_height="fill_parent" 6 > 7 <LinearLayout 8 android:layout_width="fill_parent" 9 android:layout_height="wrap_content" 10 android:orientation="vertical" 11 > 12 <EditText 13 android:layout_width="fill_parent" 14 android:layout_height="wrap_content" 15 /> 16 </LinearLayout> 17 <LinearLayout 18 android:layout_width="fill_parent" 19 android:layout_height="wrap_content" 20 android:orientation="horizontal" 21 android:gravity="right" 22 > 23 <!-- android:gravity="right"表示Button组件向右对齐 --> 24 <Button 25 android:layout_height="wrap_content" 26 android:layout_width="wrap_content" 27 android:text="确定" 28 /> 29 <Button 30 android:layout_height="wrap_content" 31 android:layout_width="wrap_content" 32 android:text="取消" 33 /> 34 </LinearLayout> 35 </LinearLayout> 第二个实例 ①效果图: ②核心代码: mian.xml 1 <?xml version="1.0" encoding="utf-8"?> 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 android:orientation="vertical" android:layout_width="fill_parent" 4 android:layout_height="fill_parent"> 5 6 <LinearLayout 7 android:orientation="horizontal" 8 android:layout_width="fill_parent" 9 android:layout_height="fill_parent" 10 android:layout_weight="1"> 11 12 <TextView 13 android:text="red" 14 android:gravity="center_horizontal" 15 android:background="#aa0000" 16 android:layout_width="wrap_content" 17 android:layout_height="fill_parent" 18 android:layout_weight="1" 19 /> 20 <!--android:gravity="center_horizontal"水平居中 --> 21 <!--layout_weight属性以控制各个控件在布局中的相对大小。layout_weight属性是一个非负整数值。 22 线性布局会根据该控件layout_weight值与其所处布局中所有控件layout_weight值之和的比值为该控件分配占用的区域。 23 例如,在水平布局的LinearLayout中有两个Button,这两个Button的layout_weight属性值都为1, 24 那么这两个按钮都会被拉伸到整个屏幕宽度的一半。如果layout_weight指为0,控件会按原大小显示,不会被拉伸; 25 对于其余layout_weight属性值大于0的控件,系统将会减去layout_weight属性值为0的控件的宽度或者高度, 26 再用剩余的宽度或高度按相应的比例来分配每一个控件显示的宽度或高度--> 27 <TextView 28 android:text="Teal" 29 android:gravity="center_horizontal" 30 android:background="#008080" 31 android:layout_width="wrap_content" 32 android:layout_height="fill_parent" 33 android:layout_weight="1"/> 34 35 <TextView 36 android:text="blue" 37 android:gravity="center_horizontal" 38 android:background="#0000aa" 39 android:layout_width="wrap_content" 40 android:layout_height="fill_parent" 41 android:layout_weight="1" 42 /> 43 44 <TextView 45 android:text="orange" 46 android:gravity="center_horizontal" 47 android:background="#FFA500" 48 android:layout_width="wrap_content" 49 android:layout_height="fill_parent" 50 android:layout_weight="1" 51 /> 52 53 </LinearLayout> 54 <LinearLayout 55 android:orientation="vertical" 56 android:layout_width="fill_parent" 57 android:layout_height="fill_parent" 58 android:layout_weight="1"> 59 60 <TextView 61 android:text="row one" 62 android:textSize="15pt" 63 android:background="#aa0000" 64 android:layout_width="fill_parent" 65 android:layout_height="wrap_content" 66 android:layout_weight="1" 67 /> 68 <!-- --> 69 <TextView 70 android:text="row two" 71 android:textSize="15pt" 72 android:background="#DDA0DD" 73 android:layout_width="fill_parent" 74 android:layout_height="wrap_content" 75 android:layout_weight="1" 76 /> 77 78 <TextView 79 android:text="row three" 80 android:textSize="15pt" 81 android:background="#008080" 82 android:layout_width="fill_parent" 83 android:layout_height="wrap_content" 84 android:layout_weight="1" 85 /> 86 <TextView 87 android:text="row four" 88 android:textSize="15pt" 89 android:background="#FFA500" 90 android:layout_width="fill_parent" 91 android:layout_height="wrap_content" 92 android:layout_weight="1" 93 /> 94 </LinearLayout> 95 </LinearLayout> 2. 帧布局 帧布局是从屏幕的左上角(0,0)坐标开始布局,多个组件层叠排列,第一个添加的组件放到最底层,最后添加到框架中的视图显示在最上面。上一层的会覆盖下一层的控件。 简单的例子 ①效果图: ②核心代码: main.xml 1 <?xml version="1.0" encoding="utf-8"?> 2 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 android:layout_width="fill_parent" 4 android:layout_height="fill_parent" 5 > 6 <TextView 7 android:layout_width="300dp" 8 android:layout_height="300dp" 9 android:background="#00BFFF" 10 /> 11 <TextView 12 android:layout_width="260dp" 13 android:layout_height="260dp" 14 android:background="#FFC0CB" 15 /> 16 <TextView 17 android:layout_width="220dp" 18 android:layout_height="220dp" 19 android:background="#0000FF" 20 /> 21 </FrameLayout> 3. 表格布局 表格布局是一个ViewGroup以表格显示它的子视图(view)元素,即行和列标识一个视图的位置。 表格布局常用的属性如下: android:collapseColumns:隐藏指定的列 android:shrinkColumns:收缩指定的列以适合屏幕,不会挤出屏幕 android:stretchColumns:尽量把指定的列填充空白部分 android:layout_column:控件放在指定的列 android:layout_span:该控件所跨越的列数 简单的例子: ①效果图: ②核心代码: main.xml 1 <?xml version="1.0" encoding="utf-8"?> 2 <TableLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 android:layout_width="fill_parent" 4 android:layout_height="fill_parent" 5 > 6 <TableRow> 7 <Button 8 android:text="Button1" 9 /> 10 <Button 11 android:text="Button2" 12 /> 13 <Button 14 android:text="Button3" 15 /> 16 </TableRow> 17 <TableRow> 18 <Button 19 android:text="Button4" 20 /> 21 <Button 22 android:layout_span="2" 23 android:text="Button5" 24 /> 25 </TableRow> 26 27 </TableLayout> 4. 相对布局 相对布局是按照组件之间的相对位置来布局,比如在某个组件的左边,右边,上面和下面等。 相对布局常用属性请参考我博客的: http://www.cnblogs.com/ECJTUACM-873284962/p/7912841.html 简单的例子 ①效果图: ② 核心代码: main.xml 1 <?xml version="1.0" encoding="utf-8"?> 2 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 android:layout_width="fill_parent" 4 android:layout_height="wrap_content" 5 android:padding="10px" 6 > 7 <TextView 8 android:id="@+id/tev1" 9 android:layout_width="wrap_content" 10 android:layout_height="wrap_content" 11 android:layout_marginBottom="30dp" 12 android:text="Please Type Here:" 13 /> 14 <EditText 15 android:id="@+id/tx1" 16 android:layout_width="match_parent" 17 android:layout_height="wrap_content" 18 android:layout_below="@id/tev1" 19 /> 20 <Button 21 android:id="@+id/btn1" 22 android:layout_height="wrap_content" 23 android:layout_width="wrap_content" 24 android:layout_below="@id/tx1" 25 android:layout_alignParentRight="true" 26 android:text="确定" 27 /> 28 <Button 29 android:id="@+id/btn2" 30 android:layout_height="wrap_content" 31 android:layout_width="wrap_content" 32 android:layout_below="@id/tx1" 33 android:layout_toLeftOf="@id/btn1" 34 android:layout_marginRight="30dp" 35 android:text="取消" 36 /> 37 </RelativeLayout> 5. 绝对布局 绝对布局通过指定子组件的确切X,Y坐标来确定组件的位置,在Android2.0 API文档中标明该类已经过期,可以使用FrameLayout或者RelativeLayout来代替。所以这里不再详细介绍。

优秀的个人博客,低调大师

Spark 概念学习系列之Apache Spark是什么?(一)

简单地说, Spark是发源于美国加州大学伯克利分校AMPLab的大数据分析平台,它立足于内存计算,从多迭代批量处理出发,兼顾数据仓库、 流处理和图计算等多种计算范式,是大数据系 统领域的全栈计算平台。 Spark是基于内存计算的大数据并行计算框架。 Spark基于内存计算,提高了在大数据环境下数据处理的实时性,同时保证了高容错性和高可伸缩性,允许用户将Spark部署在大量廉价硬件之上,形成集群。 更准确地说,Spark是一个计算框架,而Hadoop中包含计算框架MapReduce和分布式文件系统HDFS,Hadoop更广泛地说还包括在其生态系统上的其他系统,如Hbase、 Hive等。Spark是MapReduce的替代方案,而且兼容HDFS、 Hive等分布式存储层,可融入Hadoop的生态系统,以弥补缺失MapReduce的不足。 进一步地说, Spark是整个BDAS的核心组件,是一个大数据分布式编程框架,不仅实现了MapReduce的算子map函数和reduce函数及计算模型,还提供更为丰富的算子,如filter、join、groupByKey等。详细见 Spark将分布式数据抽象为弹性分布式数据集(RDD),实现了应用任务调度、RPC、序列化和压缩,并为运行在其上的上层组件提供API。其底层采用Scala这种函数式语言书写而成,并且所提供的API深度借鉴Scala函数式的编程思想,提供与Scala类似的编程接口。 图1 Spark的任务处理流程图 Spark将数据在分布式环境下分区,然后将作业转化为有向无环图(DAG),并分阶段进行DAG的调度和任务的分布式并行处理。 Spark 是什么? ● 官方文档解释:Apache Spark™is a fast and general engine for large-scale data processing. 通俗的理解:Spark是基于内存计算的大数据并行计算框架。Spark基于内存计算,提高了在大数据环境下数据处理的实时性,同时保证了高容错性和高可伸缩性,允许用户将Spark 部署在大量廉价硬件之上,形成集群。 ●扩展了MapReduce计算模型;相比与MapReduce编程模型,Spark提供了更加灵活的DAG(Directed Acyclic Graph) 编程模型, 不仅包含传统的map、reduce接口,还增加了filter、flatMap、union等操作接口,使得编写Spark程序更加灵活方便。 ● 高效支持多种计算模式;Spark 不仅可以做离线运算,还可以做流式运算以及迭代式运算。 本文转自大数据躺过的坑博客园博客,原文链接:http://www.cnblogs.com/zlslch/p/5706914.html,如需转载请自行联系原作者

优秀的个人博客,低调大师

Spark SQL概念学习系列之Spark Shark是什么?

Shark是构建在Spark和Hive基础之上的数据仓库。 目前,Shark已经完成学术使命,终止开发,但其架构和原理仍具有借鉴意义。 它提供了能够查询Hive中所存储数据的一套SQL接口,兼容现有的Hive QL语法。 这样,熟悉Hive QL或者SQL的用户可以基于Shark进行快速的Ad-Hoc、 Reporting等类型的SQL查询。 Shark底层复用Hive的解析器、 优化器以及元数据存储和序列化接口。Shark会将Hive QL编译转化为一组Spark任务,进行分布式运算。 本文转自大数据躺过的坑博客园博客,原文链接:http://www.cnblogs.com/zlslch/p/5723914.html,如需转载请自行联系原作者

优秀的个人博客,低调大师

《从零开始学Swift》学习笔记(Day 27)——可选类型

可选类型: 我们先看看如下代码: 1 2 3 4 varn1:Int= 10 n1=nil //编译错误 letstr:String=nil //编译错误 Int和String类型不能接受nil的,但程序运行过程中有时被复制给nil是在所难免的,Swift为每一种数据类型提供一种可选类型(optional),即在某个数据类型后面加上问号(?)或感叹号(!),修改前文示例代码: 1 2 3 4 varn1:Int?= 10 n1=nil letstr:String!=nil Int?和String!都是原有类型Int和String可选类型,它们可以接受nil。 可选类型值拆包 在可选类型的问号(?)或感叹号(!)究竟有什么区别呢?这与可选类型的“拆包”(unwrapping)有关,拆包是将可选类型变成普通类型,如果我们直接打印非空的可选类型值,代码如下: 1 2 varn1:Int?= 10 print(n1) 输出的结果是Optional(10),而非10。所以试图计算表达式n1+ 100会发生编译错误,代码如下: 1 2 varn1:Int?= 10 print(n1+ 100 ) //发生编译错误 需要对可选类型值进行“拆包”是必要地。 “拆包”分为显示拆包和隐性拆包。 使用问号(?)声明的可选类型,在拆包时需要使用感叹号(!),这种拆包方式称为“显式拆包”; 使用感叹号(!)声明的可选类型,在拆包时可以不使用感叹号(!),这种表示方式称为“隐式拆包”。 看看下面代码: 1 2 3 4 5 varn1:Int?= 10 print(n1!+ 100 ) //显式拆包 varn2:Int!= 100 print(n2+ 200 ) //隐式拆包 本文转自 tony关东升 51CTO博客,原文链接:http://blog.51cto.com/tonyguan/1746587,如需转载请自行联系原作者

优秀的个人博客,低调大师

Nginx 学习笔记(六)引入线程池 性能提升9倍

原文地址:https://www.cnblogs.com/shitoufengkuang/p/4910333.html 一、前言 1、Nignx版本:1.7.11 以上 2、NGINX采用了异步、事件驱动的方法来处理连接。这种处理方式无需(像使用传统架构的服务器一样)为每个请求创建额外的专用进程或者线程,而是在一个工作进程中处理多个连接和请求。 3、NGINX工作在非阻塞的socket模式下,并使用了epoll和kqueue这样有效的方法。 4、NGINX可以非常好地处理百万级规模的并发请求。 5、阻塞操作可以毁掉NGINX的性能,我们必须不惜一切代价避免使用阻塞。 6、即使在当前官方的NGINX代码中,依然无法在全部场景中避免使用阻塞,NGINX1.7.11中实现的线程池机制解决了这个问题 二、问题 1、通常情况下,NGINX是一个事件处理器,即一个接收来自内核的所有连接事件的信息,然后向操作系统发出做什么指令的控制器。 2、所谓“阻塞操作”是指任何导致事件处理循环显著停止一段时间的操作 3、操作可以由于各种原因成为阻塞操作 三、线程池 1、对NGINX而言,线程池执行的就是配货服务的功能。它由一个任务队列和一组处理这个队列的线程组成。 2、当工作进程需要执行一个潜在的长操作时,工作进程不再自己执行这个操作,而是将任务放到线程池队列中,任何空闲的线程都可以从队列中获取并执行这个任务。 3、磁盘的读取速度不能比磁盘产生数据的速度快。 4、“从磁盘读取”这个操作通常是阻塞操作最常见的示例,但是实际上,NGINX中实现的线程池可用于处理任何不适合在主循环中执行的任务。 5、线程池中执行的两个基本操作是大多数操作系统中的read()系统调用和Linux中的sendfile()。

优秀的个人博客,低调大师

Android开发学习笔记:浅谈显示Intent和隐式Intent

Intent寻找目标组件的两种方式: 显式Intent:通过指定Intent组件名称来实现的,它一般用在知道目标组件名称的前提下,一般是在相同的应用程序内部实现的。 隐式Intent:通过Intent Filter来实现的,它一般用在没有明确指出目标组件名称的前提下,一般是用于在不同应用程序之间。 一.显式Intent 一般情况下,一个Android应用程序中需要多个屏幕,即是多个Activity类,并且在这些Activity之间进行切换通过Intent机制来实现的。在同一个应用程序中切换Activity时,我们通常都知道要启动的Activity具体是哪一个,因此常用显式的Intent来实现的。 下面的例子是在同一应用程序中MainActivity启动SecondActivity,下面的代码中,主要是为“转到SecondActivity”按钮添加了OnClickListener,使得按钮被点击时执行onClick()方法,onClick()方法中则利用了Intent机制,来启动SecondActivity,关键的代码是22~25行。 main.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/hello1" /> <Button android:id="@+id/btn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="转到SecondActivity" /> </LinearLayout> second.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/hello2" /> <Button android:id="@+id/secondBtn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="返回" /> </LinearLayout> MainActivity.java package com.android.test.activity; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; public class MainActivity extends Activity { private Button btn; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); btn = (Button)findViewById(R.id.btn); //响应按钮btn事件 btn.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { //显示方式声明Intent,直接启动SecondActivity Intent it = new Intent(MainActivity.this,SecondActivity.class); //启动Activity startActivity(it); } }); } } SecondActivity.java package com.android.test.activity; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; public class SecondActivity extends Activity { private Button secondBtn; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.second); secondBtn=(Button)findViewById(R.id.secondBtn); //响应按钮secondBtn事件 secondBtn.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { //显示方式声明Intent,直接启动MainActivity Intent intent = new Intent(SecondActivity.this,MainActivity.class); //启动Activity startActivity(intent); } }); } } AndroidManifest.xml清单文件,16~18行为SecondActivity在清单文件里的声明 <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.test.activity" android:versionCode="1" android:versionName="1.0"> <uses-sdk android:minSdkVersion="10" /> <application android:icon="@drawable/icon" android:label="@string/app_name"> <activity android:name=".MainActivity" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name=".SecondActivity" android:label="@string/app_name"> </activity> </application> </manifest> 效果图: 二.隐式Intent 下面是同一应用程序中的Activity切换的例子,需要AndroidManifest.xml中增加Activity的声明,并设置对应的Intent Filter和Action,才能被Android的应用程序框架所匹配。 MainActivity.java package com.android.change.activity; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; public class MainActivity extends Activity { private Button btn; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); btn = (Button) findViewById(R.id.btn); // 响应按钮btn事件 btn.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // 实例化Intent Intent it = new Intent(); //设置Intent的Action属性 it.setAction("com.android.activity.MY_ACTION"); // 启动Activity startActivity(it); } }); } } SecondActivity.java package com.android.change.activity; import android.app.Activity; import android.os.Bundle; public class SecondActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.second); } } main.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" /> <Button android:id="@+id/btn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="转到SecondActivity" /> </LinearLayout> seond.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/second" /> </LinearLayout> AndroidManifest.xml文件的18,19行修改了Intent Filter,这样SecondActivity才能够接收到MainActivity发送的Intent。因为在MainActivity的Intent发送的动作为"com.android.activity.MY_ACTION",而在18行里,SecondActivity设置的Action也为"com.android.activity.MY_ACTION",这样就能进行匹配。 <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.change.activity" android:versionCode="1" android:versionName="1.0"> <uses-sdk android:minSdkVersion="10" /> <application android:icon="@drawable/icon" android:label="@string/app_name"> <activity android:name=".MainActivity" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name=".SecondActivity" > <intent-filter> <action android:name = "com.android.activity.MY_ACTION" /> <category android:name = "android.intent.category.DEFAULT" /> </intent-filter> </activity> </application> </manifest> 效果图: 对于显示Intent,Android不需要再去做解析,因为目标组件很明确。Android需要解析的是隐式Intent,通过解析,将Intent映射给可以处理该Intent的Activity,Service等。Intent的解析机制主要是通过查找已经注册在AndroidManifest.xml中的所有IntentFilter以及其中定义的Intent,最终找到匹配的Intent。 本文转自 lingdududu 51CTO博客,原文链接: http://blog.51cto.com/liangruijun/655132

优秀的个人博客,低调大师

《从零开始学Swift》学习笔记(Day 26)——可选链

在Swift程序表达式中会看到问号(?)和感叹号(!),它们代表什么含义呢?这些符号都与可选类型和可选链相关,下面来看看可选链。 可选链: 类图: 它们之间是典型的关联关系类图。这些类一般都是实体类,实体类是系统中的人、事、物。Employee通过dept属性与Department关联,Department通过comp属性与Company关联。 下面看示例代码: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 class Employee{ varno:Int= 0 varname:String= "Tony" varjob:String? varsalary:Double= 0 vardept:Department=Department() } class Department{ varno:Int= 10 varname:String= "SALES" varcomp:Company=Company() } class Company{ varno:Int= 1000 varname:String= "EOrient" } letemp=Employee() //Employee实例 print(emp.dept.comp.name) // emp.dept.comp.name可以引用到Company实例,形成一个引用的链条,但是这个“链条”任何一个环节“断裂”都无法引用到最后的目标(Company实例)。 给定一个Employee实例,一定会有一个Department与其关联。但现实是一个新入职员工未必有部门,这种关联关系有可能有值,也有可能没有值,我们需要使用可选类型(Department?)声明dept属性。 修改代码如下: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 class Employee{ varno:Int= 0 varname:String= "Tony" varjob:String? varsalary:Double= 0 vardept:Department? //=Department() } class Department{ varno:Int= 10 varname:String= "SALES" varcomp:Company? //=Company() } class Company{ varno:Int= 1000 varname:String= "EOrient" } letemp=Employee() print(emp.dept!.comp!.name) //显示拆包 print(emp.dept?.comp?.name) //可选链 其中可选类型的引用,可以使用感叹号(!)进行显示拆包,代码修改如下: 1 print(emp.dept!.comp!.name) 但是显示拆包有一个弊端,如果可选链中某个环节为nil,将会导致代码运行时错误。我们可以采用更加“温柔”的引用方式,使用问号(?)来代替原来感叹号(!)的位置,如下所示: 1 print(emp.dept?.comp?.name) 本文转自 tony关东升 51CTO博客,原文链接:http://blog.51cto.com/tonyguan/1746584,如需转载请自行联系原作者

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

用户登录
用户注册