Go语言之三驾马车
作者:唐郑望,腾讯后台开发 工程师
商业转载请联系腾讯WeTest获得授权,非商业转载请注明出处。
WeTest 导读
Go语言的三个核心设计: interface | goroutine | channel
less is more —— Wikipedia
从Python到Go
远离舒适区
保持饥饿感
一、interface
Go是一门面向接口编程的语言,interface的设计自然是重中之重。Go中对于interface设计的巧妙之处就在于空的interface可以被当作“Duck”类型使用,它使得Go这样的静态语言拥有了一定的动态性,却又不损失静态语言在类型安全方面拥有的编译时检查的优势。
(一)source code
从底层实现来看,interface实际上是一个结构体,包含两个成员。其中一个成员指针指向了包含类型信息的区域,可以理解为虚表指针,而另一个则指向具体数据,也就是该interface实际引用的数据。
Itab的结构如下:
其中 interfacetype 包含了一些关于interface本身的信息,_type表示具体实现类型,在下文eface中会有详细描述,bad 是一个状态变量,fun是一个长度为1的指针数组,在 fun[0] 的地址后面依次保存method对应的函数指针。go runtime 包里面有一个hash表,通过这个hash表可以取得 itab,link跟inhash则是为了保存hash表中对应的位置并设置标识。主要代码如下:

空接口的实现略有不同。Go中任何对象都可以表示为interface{},类似于C中的 void*,而且interface{}中存有类型信息。
Type的结构如下:

提示:关于interface的更多信息,可以参考:https://research.swtch.com/interfaces
(二)i_example
关于interface的应用,下面举个简单的例子,是关于Go与Mysql数据库交互的。
首先在mysql test库中创建一张任务信息表:
数据库交互最基本的四个操作:增删改查, 这里以查询为例:
Go来实现查询这张表里面的所有数据
其中

这段代码可以实现查表这个简单的逻辑,但是有一个小小的问题就是,我们这张表结构比较简单只有4个字段,如果换一张有20+个字段甚至更多的表来查询的话,这段代码就显得太过于低效,这个时候我们便可以引入interface{}来进行优化。
优化后的代码如下:

由于interface{}可以保存任何类型的数据,所以通过构造args、values两个数组,其中args的每个值指向values相应值的地址,来对数据进行批量的读取及后续操作,值得注意的是Go是一门强类型的语言,而且不同的interface{}是存有不同的类型信息的,在进行赋值等相关操作时需要进行类型转换。
Go对于Mysql事务处理也提供了比较好的支持。一般的操作使用的是db对象的方法,事务则是使用sql.Tx对象。使用db的Begin方法可以创建tx对象。tx对象也有数据库交互的Query,Exec和Prepare方法,与db的操作类似。查询或修改的操作完毕之后,需要调用tx对象的Commit()提交或者Rollback()回滚。
例如,现在需要利用事务对之前创建的user表进行update操作,代码如下
注意: “ := “ 跟 “ = “两个操作符不要弄混淆
如果不需要进行事务处理的话,update对应的代码如下

可以与上面增加事务操作的代码进行对比,因为操作比较简单所以也就增加了几行代码,以及将db对象换成了tx对象。
提示:关于Go对sql的更多支持,可以参考官方文档:https://golang.org/pkg/databa...
二、goroutine
并发:同一时间内处理(dealing with)不同的事情
并行:同一时间内做(doing)不同的事情
Go从语言层面就支持了并行,而goroutine则是Go并行设计的核心。本质上,goroutine就是协程,拥有独立的可以自行管理的调用栈,可以把goroutine理解为轻量级的thread。但是thread是操作系统调度的,抢占式的。goroutine是通过自己的调度器来调度的。
(一)scheduler
Go的调度器实现了G-P-M调度模型,其中有三个重要的结构:M,P,G
M : Machine (OS thread)
P : Context (Go Scheduler)
G : Goroutine
底层的数据结构长这样:


M、P 和 G 之间的交互可以通过下面这几张来自go runtime scheduler的图来展现
上图中看,有2个物理线程M,每一个M都拥有一个上下文P,也都有一个正在运行的goroutine G。图中灰色的那些G并没有运行,而是出于ready的就绪态,正在等待被调度。由P来维护着这个runqueue队列。
图中的M1可能是被新建出来的,也可能是从线程缓存中取出来的。当M0返回时,它必须尝试获取P来运行G,通常情况下,它会尝试从其他的thread那里”steal”一个P过来,失败的话,它就把G放在一个global runqueue里,然后自己会被放入线程缓存里。所有的P会周期性的检查global runqueue,否则global runqueue上的G永远无法执行。
另一种情况是P所分配的任务G很快就执行完了(因为分配不均),这就导致了某些P处于空闲状态而系统却依然在运行态。但如果global runqueue没有任务G了,那么P就不得不从其他的P那里拿一些G来执行。通常情况下,如果P从其他的P那里要偷一个任务的话,一般就‘steal’ runqueue的一半,这就确保了每个thread都能充分的使用。
P如何从其他P维护的队列中”steal”到G呢?这就涉及到work-stealing算法,关于该算法的更多信息可以参考:https://rakyll.org/scheduler/
(二)g_example
举个简单的例子来演示下goroutine是如何运行的
这段代码非常简单,两个不同的goroutine异步运行
运行结果如下:
然后做个小小的改动,只是将main()中的两个函数的位置互换,其余代码变:
会出现一件有意思的事情:
原因也很简单,因为main()返回时, 并不会等待其他goroutine(非主goroutine)结束。对上面的例子, 主函数执行完第一个say()后,创建了一个新的goroutine没来得及执行程序就结束了,所以会出现上面的运行结果。
三、channel
goroutine在相同的地址空间中运行,因此必须同步对共享内存的访问。Go语言提供了一个很好的通信机制channel,来满足goroutine之间数据的通信。channel与Unix shell 中的双向管道有些类似:可以通过它发送或者接收值。
source code
其中waitq的结构如下
可以看到channel其实就是一个队列加一个锁。其中sendx和recvx可以看做生产者跟消费者队列,分别保存的是等待在channel上进行读操作的goroutine和等待在channel上进行写操作的goroutine,如下图所示。
写channel (ch <- x)的具体实现如下(只选取了核心代码):
具体可以分为三种情况:
— 有goroutine阻塞在channel上,而且chanbuf为空,直接将数据发送给该goroutine上。
— chanbuf有空间可用:将数据放到chanbuf里面。
— chanbuf没有空间可用:阻塞当前goroutine。
读channel( <-ch)和发送的操作类似,就不帖代码展示了。
c_example
关于goroutine跟channel进行通信的一个简单的例子,逻辑很简单:
这里我们定义了两个带缓存的channel jobs 和 results,如果把这两个channel都换成不带缓存的,就会报错,不过可以这样进行处理就可以了:
比较常见的channel操作还有select , 存在多个channel的时候,可以通过select可以监听channel上的数据流动。
因为 ch1 和 ch2 都为空,所以 case1 和 case2 都不会读取成功。 则 select 执行 default 语句。
这篇文章是对这段时间学习Go的一次小结,也算是抛砖引玉,文中如有理解不对或者描述错误的地方,也恳请大家批评指正,关于Go的学习,更希望能与大家多多交流,谢谢!
关于腾讯WeTest (wetest.qq.com)
腾讯WeTest是腾讯游戏官方推出的一站式游戏测试平台,用十年腾讯游戏测试经验帮助广大开发者对游戏开发全生命周期进行质量保障。腾讯WeTest提供:适配兼容测试;云端真机调试;安全测试;耗电量测试;服务器性能测试;舆情分析等服务。
点击地址:http://wetest.qq.com/立即体验!
Go语言之三驾马车的更多相关文章
- Go 语言之三驾马车
interface Go是一门面向接口编程的语言,interface的设计自然是重中之重.Go中对于interface设计的巧妙之处就在于空的interface可以被当作"Duck" ...
- [MapReduce] Google三驾马车:GFS、MapReduce和Bigtable
声明:此文转载自博客开发团队的博客,尊重原创工作.该文适合学分布式系统之前,作为背景介绍来读. 谈到分布式系统,就不得不提Google的三驾马车:Google FS[1],MapReduce[2],B ...
- Google三驾马车
Google旧三驾马车: GFS,mapreduce,Bigtable http://blog.sina.com.cn/s/blog_4ed630e801000bi3.html Google新三驾马车 ...
- Childlife旗下三驾马车
Childlife旗下,尤其以 “提高免疫力”为口号的“三驾马车”:第一防御液.VC.紫雏菊,是相当热门的海淘产品.据说这是一系列“成分天然.有效治愈感冒提升免疫力.由美国著名儿科医生研发”的药物.
- 【技术与商业案例解读笔记】095:Google大数据三驾马车笔记
1.谷歌三驾马车地位 [关键词]开启时代,指明方向 聊起大数据,我们通常言必称谷歌,谷歌有“三驾马车”:谷歌文件系统(GFS).MapReduce和BigTable.谷歌的“三驾马车”开启了大数据时 ...
- 分布式系统漫谈一 —— Google三驾马车: GFS,mapreduce,Bigtable
分布式系统学习必读文章!!!! 原文:http://blog.sina.com.cn/s/blog_4ed630e801000bi3.html 分布式系统漫谈一 —— Google三驾马车: GFS, ...
- Google三驾马车:GFS、MapReduce和Bigtable
谈到分布式系统,就不得不提Google的三驾马车:Google fs[1],Mapreduce[2],Bigtable[3]. 虽然Google没有公布这三个产品的源码,但是他发布了这三个产品的详细设 ...
- Ubuntu 安装 k8s 三驾马车 kubelet kubeadm kubectl
Ubuntu 版本是 18.04 ,用的是阿里云服务器,记录一下自己实际安装过程的操作步骤. 安装 docker 安装所需的软件 apt-get update apt-get install -y a ...
- 更强、更稳、更高效:解读 etcd 技术升级的三驾马车
点击下载<不一样的 双11 技术:阿里巴巴经济体云原生实践> 本文节选自<不一样的 双11 技术:阿里巴巴经济体云原生实践>一书,点击上方图片即可下载! 作者 | 陈星宇(宇慕 ...
随机推荐
- SpringMVC第四篇【参数绑定详讲、默认支持参数类型、自定义参数绑定、RequestParam注解】
参数绑定 我们在Controller使用方法参数接收值,就是把web端的值给接收到Controller中处理,这个过程就叫做参数绑定- 默认支持的参数类型 从上面的用法我们可以发现,我们可以使用req ...
- Spring-Hibernate-web的延迟加载方案
1,现象与问题 /** * 由于Hibernate存在延迟加载问题,当Dao事务提交之后,session就关闭: * 此时如果到显示层就没有办法获取对象,使用openSessionInViewer是解 ...
- mariadb自带命令行客户端指令笔记
mysql -H 主机IP -u 用户名 -p -p表示要输密码,不要直接输了,要回车后在程序里输入 显示数据库列表: show databases; 选择XX数据库: use XX; 显示数据库里的 ...
- Spring c3p0连接池无法释放解决方案
通过c3p0配置连接池的时候,在进行压力测试的时候,日志出现了这样一个错误:Data source rejected establishment of connection, message from ...
- 【编程之外】还记得曾经给'大学导师'写过的报告嘛 --> 前方高能
写在前面 本文不是讲技术的,也没什么代码可看 本文不是讲技术的,也没什么代码可看 本文不是讲技术的,也没什么代码可看 还记得我们曾经给我们大学''导师''写过的报告嘛? 大学他愿意在凌晨6点向你询问近 ...
- 使用VUE模仿BOSS直聘APP
一.碎碎念: 偶尔在群里看到一个小伙伴说:最近面试的人好多都说用vue做过一个饿了么.当时有种莫名想笑. 为何不知道创新一下?于是想写个DEMO演练一下.那去模仿谁呢?还是BOSS直聘(跟我没关系,不 ...
- Zend Framework 3.0 安装及创建初始化项目教程
前言: 最近开始接触关于PHP的框架的学习,然而PHP的框架少说也有七八种. 百度了一下,有人说ThinkPHP简单暴力的,有人说Laravel高大上的,等等等等,难以抉择. 最终我还是选择先从接触Z ...
- 大数据 - Teradata学习体会
引言 随着计算机系统在处理能力.存储能力等方面,特别是计算机软件技术的不断提高,使得信息处理技术得到飞速发展. 数据处理主要分为两大类:联机事物处理OLTP.联机分析处理OLAP.OLTP也就是传统的 ...
- 基于MyBatis3.0.6的基本操作介绍
每 一 个 MyBatis 的 应 用 程 序 都 以 一 个 SqlSessionFactory 对 象 的 实 例 为 核 心 .SqlSessionFactory本身是由SqlSessionFa ...
- 用java编写一个微博登陆页面
上次也写了一个微博登陆页面,不过功能还不够完善.今天重新完善了一些功能,分享出来给大家. 基本功能如下: (1)具有类似新浪微博的用户注册图形界面. (2)使用用户名或手机号注册,注册时需要提供新密码 ...