您好,欢迎访问三七文档
DiveintoGolang@许式伟2013-07-192自我介绍•七牛–七牛云存储CEO–《Go语言编程》作者–《ProgramminginGo》译者•盛大–盛大创新院资深研究员–盛大祥云计划(盛大云前身)发起人–盛大网盘发起人•百度–百度网页搜索•金山–金山软件技术总监–WPSOffice2005首席架构师–金山实验室发起人•研究云存储课题Golang思维方式•最小心智负担原则–最小特性–最少惊异–最少犯错机会Golang思维方式•Go,NextJava?No,NextC!–少就是指数级的多•最少特性原则:如果一个功能不对解决任何问题有显著价值,那么就不提供–显式表达:所写即所得的语言–最对胃口的并行支持–类型系统的纲:interface–极度简化但完备的OOP•struct可以定义成员方法(method),这是Go对OOP支持的所有内容•简化的符号访问权限控制、显式的this指针–错误处理规范•函数多返回值、内置error类型、defer–功能内聚:例如,强大的组合能力–消除了堆与栈的边界消除了堆与栈的边界–最友善的C语言的支持–思维方式•Go,基于连接与组合的语言–Pipeline与并行模型•在Go中实施Pipeline非常容易•在Go中让任务并行化非常容易–连接•Go组件的连接是松散耦合的。彼此之间有最自然的独立性•Go组件间的协议由interface描述,并在编译期进行check–组合•不支持继承,却胜过继承•不是COM,但更胜COM–思维方式•以软件工程为目的的语言设计–快速编译–严格的依赖管理–代码风格的强一致性–偏向组合而不是继承–今天讲什么?•不讲库•不通盘介绍Golang特性•打破砂锅问到底–选择Golang局部特性,挖深坑DiveintoGolang•切片(slice)•接口(interface)•闭包(closure)•并行编程(concurrency)切片(slice)•数据结构–Data*type–Lenint–Capint•直观含义:数组片段–指向数组的一个区间(range)•[Data,Data+Len)•本质:动态数组–可动态扩容的数组(vector)–有Cap成员是明证切片(slice)•取数组片段–slice=array[from:to]–slice=array[:to]–slice=array[from:]–slice=array[:]•reslice–slice2=sliece[from:to]–slice2可以超出slice的范围,所以叫reslice而不是subslice–slice2不能超出底层array的范围•取区间大小/容量-len(slice)/cap(slice)•复制元素-copy(dest,src)–返回复制的元素个数:min(len(dest),len(src))–实际上如果dest是[]byte,那么src还可以是string•追加元素–append(dest,val)–append(dest,v1,v2,...,vN)–append(dest,src...)切片(slice)•示范代码arr:=[6]int{0,1,2,3,4,5}slice:=arr[1:3]slice2:=slice[1:3]•结果slice.Data=&arr[1]slice.Len=3-1=2slice.Cap=6-1=5slice={1,2}slice2.Data=&slice.Data[1]=&arr[2]slice2.Len=3-1=2slice2.Cap=slice.Cap-1=4slice2={2,3}切片(slice)•Go语言为数不多的陷阱之一arr:=[]int{1,2,3,4,5}slice:=arr[1:2]slice=append(slice,6,7,8)fmt.Println(slice)fmt.Println(arr)•信条–不对函数slice类型的参数进行append接口(interface)•数据结构–Data*type–Itbl*itbl•对比C++interface数据结构–vptr*vtable•差异–Go的interface是个值类型(可定义实例),里面含有2个指针;C++的interface不能定义实例,只能定义相应的指针类型,比如IFoo*•接口(interface)•Go接口样例varfooIFoo=new(FooImpl)foo.Bar()–翻译成CFooImpl*unnamed=newFooImpl();IFoofoo={unnamed,&FooImpl_IFoo_Itbl};foo.Itbl-Bar(foo.Data);•C++接口样例IFoo*foo=new(FooImpl);foo-Bar();–翻译成CFooImpl*unnamed=newFooImpl();IFoo*foo=(IFoo*)unnamed;foo-vptr-Bar(foo);接口(interface)•赋值(assignment)varfooIFoo=&FooImpl{...}•如果*FooImpl类型符合IFoo接口varfooIFoo=FooImpl{...}•如果FooImpl类型符合IFoo接口varbarIBar=foo•如果IFoo接口符合IBar接口,也就是IBar是IFoo要求的子集varanyinterface{}=anyVal•任何类型的实例,都可以赋值给空接口•接口查询(queryinterface)w,ok:=bar.(io.Writer)•询问bar接口指向的组件是否符合io.Writer接口•类型查询(querytype)foo,ok:=bar.(*FooImpl)•询问bar接口指向的组件是否是*FooImpl类型switchv:=bar.(type){case*FooImpl:...}•根据bar接口指向的组件类型选择闭包(closure)•原理–闭包只是带有父函数的上下文(Context)的函数•函数带有上下文并不奇怪,函数都可以访问全局变量,那就是上下文。•不同之处在于,父函数本身的状态是动态产生和消亡的,这个上下文需要有生命周期管理。但Go是gc语言,这一点上也不是问题。•闭包对父函数的Context只是引用而不复制。闭包(closure)•柯里化(currying)–对多元函数的某个参数进行绑定funcapp(inio.Reader,outio.Writer,args[]string){...}args:=[]string{arg1,arg2,...}app2:=func(inio.Reader,outio.Writer){app(in,out,args)}–Go1.1支持了对receiver的快速绑定func(recvr*App)main(inio.Reader,outio.Writer){...}app:=&App{...}app2:=app.main•等价于app2:=func(inio.Reader,outio.Writer){app.main(in,out)}闭包(closure)•闭包的组合funcpipe(app1func(io.Reader,io.Writer),app2func(io.Reader,io.Writer))func(io.Reader,io.Writer){returnfunc(inio.Reader,outio.Writer){pr,pw:=io.Pipe()deferpw.Close()gofunc(){deferpr.Close()app2(pr,out)}()app1(in,pw)}}闭包(closure)•闭包的陷阱varclosures[2]func()fori:=0;i2;i++{closures[i]=func(){fmt.Println(i)}}closures[0]()closures[1]()–不要认为会打印0和1,实际打印是2和2–修正方法varclosures[2]func()fori:=0;i2;i++{val:=iclosures[i]=func(){fmt.Println(val)}}closures[0]()closures[1]()并行编程(concurrency)•goroutine–轻量级执行体(类比:协程/纤程)–无上限(只受限于内存)、创建/切换成本低•但注意不要当做是零成本,还是应该留心创建goroutine频度与数量•channel–本质上是一个MessageQueue–非常正统的执行体间通讯设施•sync.Mutex/RWMutex/Cond/etc–不要把channel当做万金油,该Mutex还是要Mutex并行编程(concurrency)•误区–用channel来做互斥(正常应该让Mutex做)•比如多个goroutine访问一组共享变量•channel的成本–作为消息队列,channel成本原高于Mutex–成本在哪?•channel内部有Mutex,因为它本身属于共享变量•channel内部可能有Cond,用来等待或唤醒满足条件的goroutine•出让cpu并且让另一个goroutine获得执行机会,这个切换周期不低,远高于Mutex检查竞争状态的成本(后者通常只是一个原子操作)并行编程(concurrency)•用channel等别人的结果done:=make(chanResult,1)gofunc(){...done-Result{}}()...result:=-donefmt.Println(result)并行编程(concurrency)•不永久等别人的结果,对方可能有异常(考虑timeout)done:=make(chanResult,1)gofunc(){...done-Result{}}()...select{caseresult:=-done:fmt.Println(result)case-time.After(3*time.Second):fmt.Println(timeout)}并行编程(concurrency)•给多个人同样的活,谁先干完要谁的结果(考虑timeout)done:=make(chanResult,3)fori:=0;i3;i++{gofunc(){...done-Result{}}()}...select{caseresult:=-done:fmt.Println(result)case-time.After(3*time.Second):fmt.Println(timeout)}并行编程(concurrency)•生产者/消费者模型–并行编程中,多个goroutine间符合生产者/消费者模型非常常见。–channel用于生产者和消费者间的通信,并适配两者的速度。•如果生产者速度过快,那么它会channel缓冲区满时停下来等待;如果消费者速度过快,则在channel缓冲区空时停下来等待。Q&A许式伟@七牛云存储
本文标题:Dive into Golang @许式伟 2013-07-19 2 自我介绍 七牛 七牛云存储
链接地址:https://www.777doc.com/doc-3485084 .html