Slide 1

Slide 1 text

Golang  Tour By  Raymond

Slide 2

Slide 2 text

•  敢于尝试新东西,勇于面对新挑战   •  拿代码说话,拿数据说话   •  不要凭感觉,要实际去测   •  对一项新技术要切实了解其优势和劣势  

Slide 3

Slide 3 text

数据   •  16台机器,标配24个硬件线程,64GB内存   •  Linux  Kernel  2.6.32  x86_64   •  单机80万并发连接,load  0.2~0.4,CPU   总使用率  7%~10%,内存占用20GB  (res)   •  目前接入的产品约1280万在线用户   •  15亿个心跳包/天  

Slide 4

Slide 4 text

No content

Slide 5

Slide 5 text

谁在用Go   •  七牛   •  盛大   •  百度   •  360   •  支付宝   •  爱西柚…  

Slide 6

Slide 6 text

boc_go On  gitlab 需求 预研 分析 选择 开发 讨论 完成

Slide 7

Slide 7 text

液websocket

Slide 8

Slide 8 text

Goqr  on  github     测试环境:    (包含写文件io时间)   Macbook  pro    8ms  /  qr    ,  go  1.0.3     Linux  29  /  30  ,      3-­‐4  ms/  qr  ,  go  1.1   并发  /  批量输出  /  可支持web服务 QFG  on  gitlab 二维自造,加强版,  定制qr颜色图片等,  直接输出 base64

Slide 9

Slide 9 text

干脆面.. Php  >  1min     Ruby  ~  14s     Go  ~  4s     …. 1000次循环

Slide 10

Slide 10 text

Mortar  on  gitlab Key  /  value  存储     队列     数组     计数器     性能:     10w写入  19s  ,    redis  21s   100w写入207s,  redis  212s

Slide 11

Slide 11 text

Gustav  on  github

Slide 12

Slide 12 text

为什么我们需要Go语言   •  随着机器性能的提升、软件规模与复杂度 的提高,Java逐步取代了单机时代的编程之 王C语言的位置。然后Java编程的体验并未 尽如人意。历年来的编程语言排行榜显示, Java语言的市场份额在逐步下跌。Go语言此 时应运而生,Go语言官方自称Go语言的出 现是因为“近10年来开发程序之难让我们 有点沮丧”。Go希望成为互联网时代的C语 言。

Slide 13

Slide 13 text

Go语言传奇的出生 •  这里我们重点介绍一下贝尔实验室中一个叫计算科学研 究中心的部门对于操作系统和编程语言的贡献。回溯至 1969年(估计大部分读者那时候都还没出世),肯·∙汤普 逊(Ken  Thompson)和丹尼斯·∙里奇(Dennis  Ritchie)在 贝尔实验室的计算科学研究中心里开发出了Unix这个大 名鼎鼎的操作系统,还因为开发Unix而衍生出了一门同 样赫赫有名的编程语言-­‐-­‐C语言。对于很大一部分人而言, Unix就是操作系统的鼻祖,C语言也是计算机课程中最 广泛使用的编程语言。Unix和C语言在过去的几十年以 来已经造就了无数的成功商业故事,比如曾在90年代如 日中天的太阳微系统(Sun  MicroSystems),现在正如 日中天的苹果的Mac  OS  X操作系统其实也可以认为是 Unix的一个变种(FreeBSD)。

Slide 14

Slide 14 text

•  虽然已经取得了如此巨大的成就,贝尔实验室的这几个 人并没有因此而沉浸在光环中止步不前,他们从20世纪 80年代又开始了一个名为Plan  9的操作系统研究项目, 目的就是解决Unix中的一些问题,发展出一个Unix的后 续替代系统。在之后的几十年中,该研究项目又演变出 了另一个叫Inferno的项目分支,以及一个名为Limbo的 编程语言。   •  Limbo是用于开发运行在小型计算机上的分布式应用的 编程语言,它支持模块化编程,编译期和运行时的强类 型检查,进程内基于具有类型的通信通道,原子性垃圾 收集和简单的抽象数据类型。它被设计为:即便是在没 有硬件内存保护的小型设备上,也能安全运行。 •  Limbo语言被认为是Go语言的前身,不仅仅因为是同一 批人设计的语言,而是Go语言确实从Limbo语言中继承 了众多优秀的特性。

Slide 15

Slide 15 text

•  贝尔实验室后来经历了多次的动荡,包括肯·∙汤普逊在内的Plan  9项 目原班人马加入了Google。在Google,他们创造了Go语言。早在 2007年9月,Go语言还是这帮大牛的20%自由时间的实验项目。幸 运的是,到了2008年5月,Google发现了Go语言的巨大潜力,从而 开始全力支持这个项目,让这批人可以全身心投入Go语言的设计 和开发工作中。Go语言的第一个版本在2009年11月正式对外发布, 并在此后的两年内快速迭代,发展迅猛。第一个正式版本的Go语 言于2012年3月28日正式发布,让Go语言迎来了第一个引人瞩目的 里程碑。 •  基于Google对开源的一贯拥抱态度, Go语言也自然而然地选择了 开源方式发布,并使用BSD授权协议。任何人可以查看Go语言的所 有源代码,并可以为Go语言发展而奉献自己的力量。 •  Google作为Go语言的主推者,并没有简简单单地把语言推给开源 社区了事,它不仅组建了一个独立的小组全职开发Go语言,还在 自家的服务中逐步增加对Go语言的支持,比如对于Google有战略 意义的云计算平台GAE(Google  AppEngine)很早就开始支持Go语 言了。按目前的发展态势,在Google内部,Go语言有逐渐取代Java 和Python主流地位的趋势。在Google的更多产品中,我们将看到Go 语言的踪影,比如Google最核心的搜索和广告业务。   •  第一个正式版本在2012年3月28正式发布。  

Slide 16

Slide 16 text

•  下面我们再来看看Go语言的主要作者。   •  肯·∙汤普逊(Ken  Thompson):设计了B语言和C语言,创建了Unix和 Plan  9操作系统,1983年图灵奖得主,Go语言的共同作者。   •  罗布·∙派克(Rob  Pike):Unix小组的成员,参与Plan  9和Inferno操作系 统,参与  Limbo和Go语言的研发,《Unix编程环境》作者之一。   •  罗伯特·∙格里泽默(Robert  Griesemer):曾协助制作Java的HotSpot编 译器和Chrome浏览器的JavaScript引擎V8。   •  拉斯·∙    考克斯(Russ  Cox):参与Plan  9操作系统的开发,Google  Code   Search项目负责人。   •  伊安·∙泰勒(Ian  Lance  Taylor):GCC社区的活跃人物,gold连接器和 GCC过程间优化LTO的主要设计者,Zembu公司的创始人。   •  布拉德·∙菲茨帕特里克(Brad  Fitzpatrick):LiveJournal的创始人,著名 开源项目memcache的作者。  

Slide 17

Slide 17 text

Go语言考虑的关键问题 •  并行与分布式支持 •  软件工程支持 •  编程哲学的重塑   –  Go语言用批判吸收的眼光,融合众家之长,但时刻警惕特性 复杂化,极力维持语言特性的简洁,力求小而精。 –  Go语言反对函数和操作符重载 –  Go语言放弃构造和析构函数 –  Go语言支持类、类成员方法、类的组合,但反对继承,反对 虚函数和虚函数重载

Slide 18

Slide 18 text

•  提升现有编程语言对程序库等依赖性 (dependency)的管理。 •  解决多处理器的任务 Go语言的目标   简洁、快速、安全、并行、有趣 、开源、支 持泛型编程、内存管理、数组安全、编译迅 速。 Go语言的特色  

Slide 19

Slide 19 text

Go  语言能做什么? •  除了编写操作系统内核及其模块之外,Go   可以做各种应用级别的开发   •  当前最适合编写各种服务器程序(Web  服 务器,应用服务器,游戏服务器,数据存 储服务器等等)   •  GUI  桌面应用程序开发(还不成熟)   •  手机 App  开发(还不成熟)   •  教育、科学计算……

Slide 20

Slide 20 text

Go  语言的目标是什么? •  同时具备静态语言的运行效率、动态语言 的开发效率   •  类型安全、内存安全   •  优秀的并发与通信能力   •  高效、无延迟的自动化垃圾收集   •  高速编译与静态链接   •  丰富、高质量的包

Slide 21

Slide 21 text

Go  在编程语言谱系中的位置?

Slide 22

Slide 22 text

Go  在编程语言谱系中的位置?

Slide 23

Slide 23 text

Go  在编程语言谱系中的位置?

Slide 24

Slide 24 text

一、为什么选用 Go

Slide 25

Slide 25 text

1.  高并发 •  一个 Go  进程可以轻易支撑几十万上百万并 发运行的 Go  协程(只要你内存足够大)   •  O(1)  的调度   •  5KiB/goroufne  的内存开销   •  net  包:pollServer  (epoll/kqueue/iocp)  支持 大量并发连接 fd  的事件通知,同时还支持 多核并行   •  select/channel  提供卓越的例程间通信能力

Slide 26

Slide 26 text

2.  高性能 •  编译为本地机器码   •  静态链接 (CGO_ENABLED=0)   •  轻量级的 runfme  实现   •  热点代码可以直接编写 C  或 ASM,同样静 态链接进目标文件

Slide 27

Slide 27 text

3.  垃圾收集 •  不想为内存泄露问题焦头烂额   •  朴素的实现:停顿式、标记 &  清除   •  还有很大的提升空间   •  资源泄露还得自己解决

Slide 28

Slide 28 text

4.  低成本 •  学习成本低:源自 C  系,大量的 C  系程序 员可以很快上手   •  运维成本低:不需要安装各种让人头疼的 依赖,不需要搭建各种运行环境,部署非 常方便

Slide 29

Slide 29 text

5.  够用的标准库 •  net   •  encoding/gob   •  strings,  bytes,  errors,  strconv   •  regexp   •  os,  fme   •  syscall   •  sync   •  ......

Slide 30

Slide 30 text

6.  高移植性 •  多种操作系统:Linux,  FreeBSD,  Darwin,   NetBSD,  OpenBSD,  Windows   •  多种体系结构:386,  amd64,  arm(v5,v6,v7)   •  多种目标文件格式:elf/pe/macho

Slide 31

Slide 31 text

Variable  Declarafons(变量声明) var  sum  int  //  Just  a  declarafon   var  total  int  =  42  //  A  declarafon  with  inifalizafon   第一眼看上去有些奇怪,但这样是有好处的,例如下面的这个C 代码片段: int*  a,  b;   这就意味着a是一个指针,但b却不是。要声明他们都是指针必 须重复两次,但在Go中,你可以这样声明: var  a,  b  *int       当一个变量被初始化后,编译器会自动识别他的类型,所以不 必要指明其类型: var  label  =  "name"       这样var关键字也就多余了,因此作者提出了一个新的赋值操作 符声明并初始化一个新变量: name  :=  "Samuel"

Slide 32

Slide 32 text

Condifonals(条件) Go中的条件句使用If-­‐else,与C语言相同。但是它的条件不需 要包含在括号中,这将减少阅读代码时的视觉混乱。当然, 在条件之前还可以添加一个简单的声明。 result  :=  someFunc();   if  result  >  0  {    /*  Do  something  */   }  else  {    /*  Handle  error  */   }   还可以: if  result  :=  someFunc();  result  >  0  {      /*  Do  something  */   }  else  {    /*  Handle  error  */   }

Slide 33

Slide 33 text

Switches   Switches  语句也与C类似,但是在C的基础上 进行了改进。 C  代码:   int  result;   switch  (byte)  {    case  'a':    case  'b':        {            result  =  1            break        }      default:        result  =  0   }    Go  代码:   var  result  int   switch  byte  {   case  'a',  'b':      result  =  1   default:      result  =  0   }

Slide 34

Slide 34 text

Go  匹配的不仅仅是integer和character类型。 C  代码:   int  result  =  calculate();   if  (result  <  0)  {      /*  negafve  */   }  else  if  (result  >  0)  {      /*  posifve  */   }  else  {      /*  zero  */   }   Go  代码:   switch  result  :=  calculate();  true  {   case  result  <  0:      /*  negafve  */   case  result  >  0:      /*  posifve  */   default:      /*  zero  */   }   当switch的值被忽略时,假设为真,所以上述代码还可 简化为: switch  result  :=  calculate();  {   case  result  <  0:      /*  negafve  */   case  result  >  0:      /*  posifve  */   default:      /*  zero  */   }

Slide 35

Slide 35 text

包管理   l  首字母大写是public,小写是private   l  需要预先编译才能import   l  已有库   l  *nix/c标准库  -  os,rand   l  C互操作  -  C   l  Container  -  heap,list,ring,vector,hash   l  golang的词法/语法分析库  –  ast   l  网络库  -  websocket,http,json  

Slide 36

Slide 36 text

Ø 变量   ü 变量声明   var  v1  int   var  v2  string   var  v3  [10]  int   var  (            v1  int            v2  string   ) ü 变量初始化   var  v1  int  =  10        //ok   var  v2  =  10                //ok   v3  :=  10                      //ok       v2  :=  10                      //error  

Slide 37

Slide 37 text

Ø 变量   ü 变量赋值 var  v1  int   v1  =  123   i,  j  =  j,  i        //多重赋值,交换   ü 匿名变量 func  GetName  ()  (firstName,  lastName,  nickName  string)  {            return  “May”,  “Chan”,  “Chibi  Maruko”   }     _,  _,  nickName  :=  GetName  ()//仅获取nickName,  _为匿名变量 占位符  

Slide 38

Slide 38 text

Ø 常量   ü 字面常量   ü 常量定义   ü 预定义常量   const  (                //iota重置为0      c0  =  iota        //c0为0    c1  =  iota        //c1为1    c2  =  iota        //c2为2   )   ü 枚举   const  (      Sunday  =  iota      Monday     )   Go语言预定义了true, false,iota

Slide 39

Slide 39 text

Ø 类型   ü 基础类型   Ø 布尔类型  bool   Ø 整型  int8  byte  int16  int  uint  uintptr   Ø 浮点类型  float32  float64   Ø 复数类型  complex64  complex128   Ø 字符串  string   Ø 字符类型  rune   Ø 错误类型  error   Ø 指针(pointer)   Ø 数组(array)   Ø 切片(slice)   Ø 字典(map)   Ø 通道(chan)   Ø 结构体(struct)   Ø 接口(interface)   ü 复合类型  

Slide 40

Slide 40 text

Ø 流程控制   ü 条件语句 if  a  <  5  {          return  0   }  else  {          return  1   }   ü 选择语句 switch  i  {          case  0  :                      fmt.Printf  (“0”)          case  1  :                    fallthrough          case  2,  3  :                    fmt.Printf  (“2,3”)          default:                    fmt.Printf  (“default”)   }  

Slide 41

Slide 41 text

Ø 流程控制   ü 选择语句 switch    {          case  0  <=  Num  &&  Num  <=  3  :                      fmt.Printf  (“0-­‐3”)          case  4  <=  Num  &&  Num  <=  6  :                    fmt.Printf  (“4-­‐6”)   }   ü 循环语句 //case  1   sum  :=  0   for  i  :=  0;  i  <  10;  i++  {//条件表达式中也支持多重赋值          sum  +=  i   }   //case2   sum  :=  0   for  {                //相当于while,do-­‐while          sum++        //支持按标签break   }  

Slide 42

Slide 42 text

Ø 流程控制   ü 跳转语句 支持confnue、break、goto,break可按标签选择中断到哪一 个循环  

Slide 43

Slide 43 text

Ø 函数   ü 函数定义   func  Add  (a  int,  b  int)  (ret  int,  err  error)  {          if  a  <  0  ||  b  <  0  {                  err  =  errors.New  (“error”)                  return            }          return  a  +  b  ,  nil  //多重返回值   }   ü 匿名函数和闭包   函数的基本组成为:关键字func、函数名、参数列表、返回值、 函数体和返回语句。 匿名函数由一个不带函数名的函数声明和函数体组成。匿名函 数可以直接赋值给一个变量或直接执行。   闭包是可以包含自由变量的代码块。相当于Java中的嵌套匿名类  

Slide 44

Slide 44 text

Ø 错误处理   ü 大多数函数将error作为最后一个返回值   ü defer   func  CopyFile  (dst,  src  string)  (w  int64,  err  error)   {        srcFile,  err  :=  os.Open  (src)        if  err  !=  nil  {              return        }        defer  srcFile.Close  ()   }     //清理多语句,使用匿名函数   defer  func  ()  {          //清理工作   }  () defer语句的含义是不管程序是否出现异常,均在函数退出时自动 执行相关代码。

Slide 45

Slide 45 text

面向对象编程   Ø 类型系统                Go语言中的大多数类型都是值语义,并且都可以包含 对应的操作方法。在需要的时候,你可以给任何类型(包括 内置类型)增加新方法。而在实现某个接口时,无需从从该 接口继承,只需要实现该接口要求的所有方法即可。   type  Integer  int   func  (a  Integer)  Less  (b  Integer)  bool  {          return  a  <  b   }   func  main  ()  {          var  a  Integer    =  1          if  a.Less  (2)  {                  fmt.Println  (a,  “Less  2”)          }   }

Slide 46

Slide 46 text

Ø 可见性   Go语言中要使某个符号对其他包(package)可见,只需要 将该符号定义为以大写字母开头,否则不可见。成员方法和 成员变量的可见性遵循同样的规则。Go语言中符号的可访问 性是包一级的而不是类型一级的。   type  Rect  struct  {          X,  Y  float64          Width,  Height  float64   }     func  (r  *Rect)  area  ()  float64  {          return  r.Width  *  r.Height   }  

Slide 47

Slide 47 text

Ø 接口   ü 非侵入式接口   type  File  struct  {            //  …   }     func  (f  *File)  Read  (buf  []  byte)  (n  int,  err  error)   func  (f  *File)  Write  (buf  []  byte)  (n  int,  err   error)   func  (f  *File)  Close  ()  error   在Go语言中,一个类只要实现了接口要求的所有函数,我们就说 这个类实现了该接口。   这种方式有如下几种好处:   • Go语言不需要绘制类库的继承树图   • 实现类的时候,只需要关心自己应该提供哪些方法,不用纠 结接口需要拆的多细才合适。   • 不用为了实现一个接口而导入一个包,减少耦合。  

Slide 48

Slide 48 text

4 Ø 接口   type  IFile  interface  {          Read  (buf  []  byte)  (n  int,  err  error)          Write  (buf  []  byte)  (n  int,  err  error)          Close  ()  error   }   type    IReader  interface  {          Read  (buf  []  byte)  (n  int,  err  error)   }   type  IWriter  interface  {          Write  (buf  []  byte)  (n  int,  err  error)   }   type  ICloser  interface  {          Close  ()  error   }   var  file1  IFile  =  new  (File)   var  file2  IReader  =  new  (File)   var  file3  IWriter  =  new  (File)   var  file4  ICloser  =  new  (File)  

Slide 49

Slide 49 text

并发编程   Ø 协程   Go语言在语言级别支持轻量级线程(即协程),叫goroutine。Go 语言提供的所有系统调用操作都会出让CPU给其他goroutine。这让 事情变得非常简单,让轻量级线程的切换管理不依赖于系统的线程和 进程,也不依赖于CPU的核心数量。   Go语言中最重要的一个特性是go关键字     func  Add  (x,  y  int)  {            z  :=  x  +  y   }       go  Add  (2,  1)        //并发执行

Slide 50

Slide 50 text

Ø 并发通信   工程上两种最常见的并发通信模型:   ü 共享数据   ü 消息   一个大的系统中具有无数的锁、无数的共享变量、无数的业务逻辑与 错误处理分支。采用共享数据将是一场噩梦。Go语言已并发编程作为 最核心优势,提供了以消息机制而非共享内存作为通信方式的通信模 型(channel)。     channel是类型相关的的,一个channel只能传递一种类型的值,这个 类型需要在声明的channel时指定。channel相当于一种类型安全的管 道。  

Slide 51

Slide 51 text

Ø 并发通信   ü channel   select  {          case  <-­‐  chan1  :          case  chan2  <-­‐  1  :          default  :   } 一般channel的声明形式:var  chanName  chan  ElementType   定义一个channel:ch  :=  make  (chan  int)   将一个数据写入channel:ch    <-  value   从channel中读取数据:value  :=  <-  ch   ü select   Go语言直接在语言级别支持select关键字,用于处理异步IO问 题。   select有比较多的限制,其中最大的限制就是每个case语句里 必须是一个IO操作。  

Slide 52

Slide 52 text

Ø 并发通信   ü 缓冲机制   timeout  :=  make  (chan  bool,  1)   go  func  ()  {            time.Sleep  (1e9)  //等待1秒            timeout  <-­‐  true   }  ()   select  {          case  <-­‐  ch  :          case  <-­‐  timeout  :          default  :   } 创建一个带缓冲的channel:c  :=  make  (chan  int,  1024)   ü 超时机制   Go语言没有提供直接的超时处理机制,但我们可以利用select 机制实现一套  

Slide 53

Slide 53 text

Ø 并发通信   ü channel的传递   type  PipeData  struct  {          value  int          handler  func  (int)  int          next  chan  int   }     func  handler  (queue  chan  *PipeData)  {          for  data  :=  range  queue  {                    data.next  <-­‐  data.handler  (data.value)          }   } Go语言中channel本身是一个原生类型,因此channel可以传递。   下面我们利用这个特性来实现*nix常见的管道特性  

Slide 54

Slide 54 text

Ø 并发通信   ü 单向channel   var  ch1  chan  int              //ch1是一个正常的channel,不是单向的   var  ch2  chan<-­‐  float64  //ch2是单向的,只用于写float64数据   var  ch3  <-­‐chan  int          //ch3是单向的,只用于读取int数据     //单向channel与双向channel之间的转换   ch4  :=  make  (chan  int)   ch5  :=  <-­‐chan  int  (ch4)        //ch5为单向的读取channel   ch6  :=  chan<-­‐  int  (ch4)        //ch6为单向的写入channel 我们在将一个channel变量传递到一个函数时,可以通过将其制定为单向 channel变量,从而限制该函数中可以对此channel的操作。  

Slide 55

Slide 55 text

Ø 多核并行化   我们可以通过设置环境变量GOMAXPROCS的值来控制使用多少个 CPU核心。   runtime.GOMAXPROCS  (16)   runtime包中还提供了一个函数NumCPU  ()来获取CPU核心数。   Go语言提供了一个Once类型来保证全局的唯一性操作。Once的Do     ()方法可以保证在全局范围内只调用指定的函数一次,而且所有其他 goroutine在调用到此语句时,将会先被阻塞,直至全局唯一的 Once.Do  ()调用结束才继续。   Ø 全局唯一性操作