Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Golang Tour part1

Golang Tour part1

RaymondChou

May 23, 2013
Tweet

More Decks by RaymondChou

Other Decks in Technology

Transcript

  1. 数据   •  16台机器,标配24个硬件线程,64GB内存   •  Linux  Kernel  2.6.32  x86_64

      •  单机80万并发连接,load  0.2~0.4,CPU   总使用率  7%~10%,内存占用20GB  (res)   •  目前接入的产品约1280万在线用户   •  15亿个心跳包/天  
  2. 谁在用Go   •  七牛   •  盛大   •  百度

      •  360   •  支付宝   •  爱西柚…  
  3. 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
  4. 干脆面.. Php  >  1min     Ruby  ~  14s  

      Go  ~  4s     …. 1000次循环
  5. Mortar  on  gitlab Key  /  value  存储     队列

        数组     计数器     性能:     10w写入  19s  ,    redis  21s   100w写入207s,  redis  212s
  6. Go语言传奇的出生 •  这里我们重点介绍一下贝尔实验室中一个叫计算科学研 究中心的部门对于操作系统和编程语言的贡献。回溯至 1969年(估计大部分读者那时候都还没出世),肯·∙汤普 逊(Ken  Thompson)和丹尼斯·∙里奇(Dennis  Ritchie)在 贝尔实验室的计算科学研究中心里开发出了Unix这个大 名鼎鼎的操作系统,还因为开发Unix而衍生出了一门同

    样赫赫有名的编程语言-­‐-­‐C语言。对于很大一部分人而言, Unix就是操作系统的鼻祖,C语言也是计算机课程中最 广泛使用的编程语言。Unix和C语言在过去的几十年以 来已经造就了无数的成功商业故事,比如曾在90年代如 日中天的太阳微系统(Sun  MicroSystems),现在正如 日中天的苹果的Mac  OS  X操作系统其实也可以认为是 Unix的一个变种(FreeBSD)。
  7. •  虽然已经取得了如此巨大的成就,贝尔实验室的这几个 人并没有因此而沉浸在光环中止步不前,他们从20世纪 80年代又开始了一个名为Plan  9的操作系统研究项目, 目的就是解决Unix中的一些问题,发展出一个Unix的后 续替代系统。在之后的几十年中,该研究项目又演变出 了另一个叫Inferno的项目分支,以及一个名为Limbo的 编程语言。  

    •  Limbo是用于开发运行在小型计算机上的分布式应用的 编程语言,它支持模块化编程,编译期和运行时的强类 型检查,进程内基于具有类型的通信通道,原子性垃圾 收集和简单的抽象数据类型。它被设计为:即便是在没 有硬件内存保护的小型设备上,也能安全运行。 •  Limbo语言被认为是Go语言的前身,不仅仅因为是同一 批人设计的语言,而是Go语言确实从Limbo语言中继承 了众多优秀的特性。
  8. •  贝尔实验室后来经历了多次的动荡,包括肯·∙汤普逊在内的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正式发布。  
  9. •  下面我们再来看看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的作者。  
  10. Go语言考虑的关键问题 •  并行与分布式支持 •  软件工程支持 •  编程哲学的重塑   –  Go语言用批判吸收的眼光,融合众家之长,但时刻警惕特性

    复杂化,极力维持语言特性的简洁,力求小而精。 –  Go语言反对函数和操作符重载 –  Go语言放弃构造和析构函数 –  Go语言支持类、类成员方法、类的组合,但反对继承,反对 虚函数和虚函数重载
  11. Go  语言能做什么? •  除了编写操作系统内核及其模块之外,Go   可以做各种应用级别的开发   •  当前最适合编写各种服务器程序(Web  服

    务器,应用服务器,游戏服务器,数据存 储服务器等等)   •  GUI  桌面应用程序开发(还不成熟)   •  手机 App  开发(还不成熟)   •  教育、科学计算……
  12. Go  语言的目标是什么? •  同时具备静态语言的运行效率、动态语言 的开发效率   •  类型安全、内存安全   • 

    优秀的并发与通信能力   •  高效、无延迟的自动化垃圾收集   •  高速编译与静态链接   •  丰富、高质量的包
  13. 1.  高并发 •  一个 Go  进程可以轻易支撑几十万上百万并 发运行的 Go  协程(只要你内存足够大)  

    •  O(1)  的调度   •  5KiB/goroufne  的内存开销   •  net  包:pollServer  (epoll/kqueue/iocp)  支持 大量并发连接 fd  的事件通知,同时还支持 多核并行   •  select/channel  提供卓越的例程间通信能力
  14. 2.  高性能 •  编译为本地机器码   •  静态链接 (CGO_ENABLED=0)   • 

    轻量级的 runfme  实现   •  热点代码可以直接编写 C  或 ASM,同样静 态链接进目标文件
  15. 4.  低成本 •  学习成本低:源自 C  系,大量的 C  系程序 员可以很快上手  

    •  运维成本低:不需要安装各种让人头疼的 依赖,不需要搭建各种运行环境,部署非 常方便
  16. 5.  够用的标准库 •  net   •  encoding/gob   •  strings,

     bytes,  errors,  strconv   •  regexp   •  os,  fme   •  syscall   •  sync   •  ......
  17. 6.  高移植性 •  多种操作系统:Linux,  FreeBSD,  Darwin,   NetBSD,  OpenBSD,  Windows

      •  多种体系结构:386,  amd64,  arm(v5,v6,v7)   •  多种目标文件格式:elf/pe/macho
  18. 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"
  19. 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  */   }
  20. 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   }
  21. 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  */   }
  22. 包管理   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  
  23. Ø 变量   ü 变量声明   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  
  24. Ø 变量   ü 变量赋值 var  v1  int   v1  =  123

      i,  j  =  j,  i        //多重赋值,交换   ü 匿名变量 func  GetName  ()  (firstName,  lastName,  nickName  string)  {            return  “May”,  “Chan”,  “Chibi  Maruko”   }     _,  _,  nickName  :=  GetName  ()//仅获取nickName,  _为匿名变量 占位符  
  25. Ø 常量   ü 字面常量   ü 常量定义   ü 预定义常量   const  (

                   //iota重置为0      c0  =  iota        //c0为0    c1  =  iota        //c1为1    c2  =  iota        //c2为2   )   ü 枚举   const  (      Sunday  =  iota      Monday     )   Go语言预定义了true, false,iota
  26. Ø 类型   ü 基础类型   Ø 布尔类型  bool   Ø 整型  int8  byte

     int16  int  uint  uintptr   Ø 浮点类型  float32  float64   Ø 复数类型  complex64  complex128   Ø 字符串  string   Ø 字符类型  rune   Ø 错误类型  error   Ø 指针(pointer)   Ø 数组(array)   Ø 切片(slice)   Ø 字典(map)   Ø 通道(chan)   Ø 结构体(struct)   Ø 接口(interface)   ü 复合类型  
  27. Ø 流程控制   ü 条件语句 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”)   }  
  28. Ø 流程控制   ü 选择语句 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   }  
  29. Ø 函数   ü 函数定义   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中的嵌套匿名类  
  30. Ø 错误处理   ü 大多数函数将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语句的含义是不管程序是否出现异常,均在函数退出时自动 执行相关代码。
  31. 面向对象编程   Ø 类型系统              

     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”)          }   }
  32. Ø 接口   ü 非侵入式接口   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语言不需要绘制类库的继承树图   • 实现类的时候,只需要关心自己应该提供哪些方法,不用纠 结接口需要拆的多细才合适。   • 不用为了实现一个接口而导入一个包,减少耦合。  
  33. 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)  
  34. Ø 并发通信   工程上两种最常见的并发通信模型:   ü 共享数据   ü 消息   一个大的系统中具有无数的锁、无数的共享变量、无数的业务逻辑与 错误处理分支。采用共享数据将是一场噩梦。Go语言已并发编程作为

    最核心优势,提供了以消息机制而非共享内存作为通信方式的通信模 型(channel)。     channel是类型相关的的,一个channel只能传递一种类型的值,这个 类型需要在声明的channel时指定。channel相当于一种类型安全的管 道。  
  35. Ø 并发通信   ü 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操作。  
  36. Ø 并发通信   ü 缓冲机制   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 机制实现一套  
  37. Ø 并发通信   ü 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常见的管道特性  
  38. Ø 并发通信   ü 单向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的操作。  
  39. Ø 多核并行化   我们可以通过设置环境变量GOMAXPROCS的值来控制使用多少个 CPU核心。   runtime.GOMAXPROCS  (16)   runtime包中还提供了一个函数NumCPU  ()来获取CPU核心数。

      Go语言提供了一个Once类型来保证全局的唯一性操作。Once的Do     ()方法可以保证在全局范围内只调用指定的函数一次,而且所有其他 goroutine在调用到此语句时,将会先被阻塞,直至全局唯一的 Once.Do  ()调用结束才继续。   Ø 全局唯一性操作