目录 基础概念 内存管理单元 内存管理组件 mcache mcentral mheap 内存分配流程 总结 参考资料 Go语言内置运行时(就是runtime),抛弃了传统的内存分配方式,改为自主管理。这样可以自主地实现更好的内存使用模式,比如内存池、预分配等等。这样,不会每次内存分配都需要进行系统调用。 Golang运行时的内存分配算法主要源自 Google 为 C 语言开发的TCMalloc算法,全称Thread-Caching Malloc。核心思想就是把内存分为多级管理,从而降低锁的粒度。...
-
图解Go语言内存分配
-
深度解密Go语言之Slice
目录 当我们在说 slice 时,到底在说什么 slice 的创建 直接声明 字面量 make 截取 slice 和数组的区别在哪 append 到底做了什么 为什么 nil slice 可以直接 append 传 slice 和 slice 指针有什么区别 总结 参考资料 Go 语言的 slice 很好用,不过也有一些坑。slice 是 Go 语言一个很重要的数据结构。网上已经有很多文章写过了,似乎没必要再写。但是每个人看问题的视角不同,写出来的东西自然也不一样。我这篇会从更底层的汇编语言去解...
-
深度解密Go语言之map
这篇文章主要讲 map 的赋值、删除、查询、扩容的具体执行过程,仍然是从底层的角度展开。结合源码,看完本文一定会彻底明白 map 底层原理。我要说明的是,这里对 map 的基本用法涉及比较少,我相信可以通过阅读其他入门书籍了解。本文的内容比较深入,但是由于我画了各种图,我相信很容易看懂。放上本文的内容提纲:什么是 map维基百科里这样定义 map:In computer science, an associative array, map, symbol table, or dictionary...
-
golang进阶(八)——隐藏技能go:linkname
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/lastsweetop/article/details/78830772 什么是go:linkname 指令的格式如下: //go:linkname hello github.com/lastsweetop/testlinkname/hello.hellofunc go:linkname引导编译器将当前(私有)方法或者变量在编译时链接到指定的位置的方法或者变量,第一个参数表示当前方法或变量,第二个参...
-
深度解密Go语言之反射
反射和 Interface 息息相关,而 Interface 是我们上一篇文章的内容。在开始正文前,和大家说点题外话。上一篇关于 Interface 的文章发出后,获得了很多的关注和阅读。比如,登上了 GoCN 的每日新闻第一条:可能是编辑者觉得这篇文章称不上“深度解密”,把标题给小小地改动了下,哈哈~~在博客园登上了 48 小时阅读排行榜:在开发者头条 APP (类似于今日头条,不过内容都是技术相关的,还挺有意思的)上收获了 150 收藏,并被推荐到首页最显眼的 banner 位置,阅读量达到...
-
深度解密Go语言之关于 interface 的 10 个问题
这次文章依然很长,基本上涵盖了 `interface` 的方方面面,有例子,有源码分析,有汇编分析,前前后后写了 20 多天。洋洋洒洒,长篇大论,依然有些东西没有涉及到,比如文章里没有写到`反射`,当然,后面会单独写一篇关于`反射`的文章,这是后话。 还是希望你在看完文章后能有所收获,有任何问题或意见建议,欢迎在文章后面留言。 这篇文章的架构比较简单,直接抛出 10 个问题,一一解答。 ![](https://static.studygolang.com/190425/92cc681d50...
-
Go work-stealing 调度器
本文译自 Rakyll 的 scheduler版权@归原文所有. Go 调度器的工作是将可运行的 goroutine 分发到一个或多个处理器上运行的多个操作系统工作线程. 在多线程计算里, 调度出现了两种模式: work-sharing (工作共享) 和 work-stealing (工作窃取). work-sharing 当一个处理器产生新的线程时, 它试图将其中的一些迁移到其他处理器上, 希望它们能被空闲或未充分利用的处理器所利用. work-stealing 未充分利用的处理器会主动去寻找...
-
图解Go select语句原理
Go 的select语句是一种仅能用于channl发送和接收消息的专用语句,此语句运行期间是阻塞的;当select中没有case语句的时候,会阻塞当前的groutine。所以,有人也会说select是用来阻塞监听goroutine的。 还有人说:select是Golang在语言层面提供的I/O多路复用的机制,其专门用来检测多个channel是否准备完毕:可读或可写。 以上说法都正确。 ## I/O多路复用 我们来回顾一下是什么是``I/O多路复用``。 ### 普通多线...
-
浅谈 Go 语言 select 的实现原理
Home Menu 浅谈 Go 语言 select 的实现原理 30 Mar 2019 Select Channel 并发编程 Golang Go实现原理 概述 结构 现象 非阻塞的收发 随机执行 编译期间 直接阻塞 独立情况 非阻塞操作 发送 接收 通用情况 运行时 初始化 循环 总结 相关文章 Reference 很多 C 语言或者 Unix 开发者听到 select 想到的都是系统调用,而谈到 I/O 模型时最终大都会提到基于 select、poll 和 epoll 等函数构建的 IO 多...
-
Go 语言 Channel 实现原理精要
Home Menu Go 语言 Channel 实现原理精要 23 Mar 2019 Channel 并发编程 Golang Go实现原理 概述 设计原理 数据结构 基本操作 创建 发送 直接发送 缓冲区 阻塞发送 小结 接收 直接接收 缓冲区 阻塞接收 小结 关闭 总结 相关文章 Reference 这一节中的内容总共包含两个部分,我们会先介绍 Channel 的设计原理以及它在 Go 语言中的数据结构,接下来我们会分析常见的 Channel 操作,例如创建、发送、接收和关闭的实现原理,由于在...
-
Go 语言 for 和 range 的实现
Home Menu Go 语言 for 和 range 的实现 17 Mar 2019 for range 循环 Golang Go实现原理 概述 永不停止的循环 神奇的指针 遍历清空数组 随机的遍历顺序 经典循环 范围循环 数组和切片 哈希 字符串 通道 总结 Reference 循环是几乎所有编程语言都具有的控制结构,也是编程语言中常用的控制结构,Go 语言除了使用经典的『三段式』循环之外,还引入了另一个关键字 range 帮助我们快速遍历数组、哈希表以及 Channel 等元素。 在这一节...
-
谈 Golang 中的字符串和字节数组
Home Menu 谈 Golang 中的字符串和字节数组 11 Mar 2019 字符串 字节 Golang Go实现原理 编译原理 运行时 概述 结构 解析 操作 拼接 类型转换 总结 相关文章 Reference 字符串是 Go 语言中最常用的基础数据类型之一,虽然字符串往往都被看做是一个整体,但是实际上字符串是一片连续的内存空间,我们也可以将它理解成一个由字符组成的数组,Go 语言中另外一个与字符串关系非常密切的类型就是字节(Byte)了,相信各位读者也都非常了解,这里也就不展开介绍。 ...
-
理解 Golang 哈希表 Map 的原理
Home Menu 理解 Golang 哈希表 Map 的原理 09 Mar 2019 哈希表 Map 拉链法 Golang Go实现原理 编译原理 运行时 概述 哈希函数 冲突解决 开放寻址法 拉链法 初始化 结构体 字面量 运行时 操作 访问 写入 扩容 删除 总结 相关文章 Reference 在上一节中我们介绍了 数组和切片的实现原理,这一节会介绍 Golang 中的另一个集合元素 — 哈希,也就是 Map 的实现原理;哈希表是除了数组之外,最常见的数据结构,几乎所有的语言都会有数组和哈...
-
Go 语言数组和切片的原理
Home Menu Go 语言数组和切片的原理 20 Feb 2019 数组 切片 Golang Go实现原理 编译原理 运行时 数组 创建 上限推导 语句转换 访问和赋值 切片 结构 初始化 字面量 关键字 访问 追加 拷贝 总结 相关文章 Reference 数组和切片是 Go 语言中常见的数据结构,很多刚刚使用 Go 的开发者往往会混淆这两个概念,数组作为最常见的集合在编程语言中是非常重要的,除了数组之外,Go 语言引入了另一个概念 — 切片,切片与数组有一些类似,但是它们的不同之处导致使...
-
指令集架构、机器码与 Go 语言
Home Menu 指令集架构、机器码与 Go 语言 08 Feb 2019 Golang Go实现原理 编译原理 机器码 指令集 汇编语言 指令集架构 分类 小结 机器码生成 SSA 降级 汇编器 总结 相关文章 Reference Go 语言编译的最后一个阶段就是根据 SSA 中间代码生成机器码了,这里谈的机器码生成就是在目标 CPU 架构上能够运行的代码,中间代码生成 一节简单介绍的从抽象语法树到 SSA 中间代码的处理过程,处理 SSA 的将近 50 个步骤中有一些过程严格上来说其实是属...
-
详解 Golang 中间代码生成
Home Menu 详解 Golang 中间代码生成 04 Feb 2019 Golang Go实现原理 SSA 编译原理 中间代码 中间代码生成 配置初始化 遍历和替换 Channel 编译 AST 到 SSA 多轮转换 总结 相关文章 Reference 前两节介绍的 词法与语法分析 以及 类型检查 两个部分都属于编译器前端,它们负责对源代码进行分析并检查其中存在的词法和语法错误,经过这两个阶段生成的抽象语法树已经不存在任何的结构上的错误了,从这一节开始就进入了编译器后端的工作 — 中间代码...
-
Golang 如何进行类型检查
Home Menu Golang 如何进行类型检查 03 Feb 2019 Golang Go实现原理 编译原理 类型检查 强弱类型 抽象语法树 AST 强弱类型 静态与动态类型 静态类型检查 动态类型检查 小结 Go 语言的类型检查 执行流程 切片 OTARRAY 哈希 OTMAP 关键字 OMAKE 总结 相关文章 Reference 我们在上一节中介绍了 Golang 的第一个编译阶段 — 通过 词法和语法分析器 的解析得到了抽象语法树,在这里就会继续介绍编译器执行的下一个过程 — 类型检...
-
解析器眼中的 Go 语言
Home Menu 解析器眼中的 Go 语言 02 Feb 2019 Golang Go实现原理 编译原理 词法分析 语法分析 抽象语法树 词法分析 lex Go 语法分析 文法 分析方法 自顶向下 自底向上 Lookahead Go 辅助方法 节点 总结 相关文章 Reference 代码其实就是按照约定格式编写的一堆字符串,工程师可以在脑内对语言的源代码进行编译并运行目标程序,这是因为经过训练的软件工程师能够对本来无意义的字符串进行分组和分析,按照约定的语法来理解源代码。既然工程师能够按照一...
-
Go 语言编译过程概述
Home Menu Go 语言编译过程概述 01 Feb 2019 Golang Go实现原理 编译原理 预备知识 抽象语法树 静态单赋值 指令集架构 编译原理 词法与语法分析 类型检查 中间代码生成 机器码生成 编译器入口 总结 相关文章 Reference Golang 是一门需要编译才能运行的编程语言,也就说代码在运行之前需要通过编译器生成二进制机器码,随后二进制文件才能在目标机器上运行,如果我们想要了解 Go 语言的实现原理,理解它的编译过程就是一个没有办法绕过的事情。 这一节会先对 G...
-
理解 Golang 中函数调用的原理
Home Menu 理解 Golang 中函数调用的原理 20 Jan 2019 Golang Go实现原理 函数调用 调用惯例 参数传递 调用惯例 C 语言 Golang 参数传递 整型和数组 结构体和指针 小结 总结 Reference 函数是 Go 语言中的一等公民,理解和掌握函数的调用过程是深入学习 Golang 时无法跳过的步骤,这里会介绍 Go 语言中函数调用的过程和实现原理并与 C 语言中函数执行的过程进行对比,同时对参数传递的原理进行剖析,让读者能够清楚地知道 Go 在函数的执行...
-
GO 中的调度:第三部分 - 并发
## 前奏 这篇文章是三部曲系列文章中的第三篇,这个系列的文章将会对 Go 中调度器背后的机制和语义做深入的了解。本文主要关注并发的部分。 Go 调度器系列文章: - [Go 中的调度器:第一部分 - 操作系统调度器](https://studygolang.com/articles/14264) - [Go 中的调度器:第二部分 - Go 调度器](https://studygolang.com/articles/15316) - [Go 中的调度器:第三部分 - 并发]...
-
Go GC
大家好,我是 Okada([@ocadaruma](https://twitter.com/ocadaruma)),LINE 广告平台团队的成员。我对 Go 的 GC (垃圾收集器)有点感兴趣,甚至还促使我专门写一篇关于它的博客。Go 是一门由 Google 开发,并且支持垃圾收集的编程语言。Go 通过[管道](https://tour.golang.org/concurrency/2) 支持并发。很多的公司,包括 Google,都在使用 Go,LINE 也用 Go 来开发工具和服务。 #...
-
Golang - 调度剖析【第二部分】
回顾本系列的第一部分,重点讲述了操作系统调度器的各个方面,这些知识对于理解和分析 Go 调度器的语义是非常重要的。在本文中,我将从语义层面解析 Go 调度器是如何工作的,并重点介绍其高级特性。Go 调度器是一个非常复杂的系统,我们不会过分关注一些细节,而是侧重于剖析它的设计模型和工作方式。我们通过学习它的优点以便够做出更好的工程决策。 开始 当 Go 程序启动时,它会为主机上标识的每个虚拟核心提供一个逻辑处理器(P)。如果处理器每个物理核心可以提供多个硬件线程(超线程),那么每个硬件线程都将作为...
-
Golang - 调度剖析【第一部分】
简介 首先,Golang 调度器的设计和实现让我们的 Go 程序在多线程执行时效率更高,性能更好。这要归功于 Go 调度器与操作系统(OS)调度器的协同合作。不过在本篇文章中,多线程 Go 程序在设计和实现上是否与调度器的工作原理完全契合不是重点。重要的是对系统调度器和 Go 调度器,它们是如何正确地设计多线程程序,有一个全面且深入的理解。 本章多数内容将侧重于讨论调度器的高级机制和语义。我将展示一些细节,让你可以通过图像来理解它们是如何工作的,可以让你在写代码时做出更好的决策。因为原理和语义是...
-
Go 语言的内存管理
这篇博客是我在维尔纽斯的 [Go Meetup](https://www.meetup.com/Vilnius-Golang/events/249897910/) 演讲的总结。如果你在维尔纽斯并且喜欢 Go 语言,欢迎加入我们并考虑作演讲 在这篇博文中我们将要探索 Go 语言的内存管理,首先让我们来思考以下的这个小程序: ```go func main() { http.HandleFunc("/bar", func(w http.ResponseWriter, r *h...
-
深入理解 sync.RWMutex:解决读者-写者问题
在某个数据需要被多个线程共享访问的时候,会出现读者-写者问题(这里的「问题」是复数形式的,因为读者-写者问题有多个变种)。访问共享数据的线程有两种类型:读者和写者。读者只会读取数据,而写者则是修改它。当写者拥有了访问数据的权限后,其它的线程(不管是读者还是写者)都不能访问这个数据。这种约束的需求在现实中是存在的,比如:当写者不能原子性地修改某个数据(例如数据库)时,在修改完成之前,要读取这个数据的读者要被阻塞,以免读者获取到损坏的数据(脏数据)。对于读者-写者问题的核心,还有很多修订的限制,比如...
-
解剖Go语言map底层实现
``map``是Go语言中基础的数据结构,在日常的使用中经常被用到。但是它底层是如何实现的呢? # ``map``的整体结构图 Golang中``map``的底层实现是一个散列表,因此实现``map``的过程实际上就是实现散表的过程。在这个散列表中,主要出现的结构体有两个,一个叫``hmap``(``a header for a go map``),一个叫``bucket``。这两种结构的样子分别如下所示: hmap: ![hmap.png](http...
-
关于Go GC - Rick's ISMM keynote
Go Blog上最近发表了一篇文章,内容是Richard Hudson在ISMM 2018上面的"Getting to Go"的讲座,包括keynote以及笔记,从中可以看到Go GC设计的考量,以及演进的脉络,文章下面摘要一些内容出来。<img src="https://pic4.zhimg.com/v2-68df7587655b337855d9cb333895d463_b.jpg" data-caption="" data-size="normal" data-rawwidth="960" ...
-
Go 逃逸分析的缺陷
## 序 先阅读这个由四部分组成的系列文章,对理解逃逸分析和数据语义会有帮助。下面详细介绍了阅读逃逸分析报告和 pprof 输出的方法。(GCTT 已经在翻译中) <https://www.ardanlabs.com/blog/2017/05/language-mechanics-on-stacks-and-pointers.html> ## 介绍 即使使用了 Go 4 年,我仍然会被这门语言震惊到。多亏了编译器执行的静态代码分析,编译器可以对其生成的代码进行一些有趣的优...
-
Go 内存逃逸详细分析
Slice 怪异现象分析实例 原贴地址:https://gocn.io/question/1852 package main import ( "fmt" ) func main(){ s := []byte("") s1 := append(s, 'a') s2 := append(s, 'b') // 如果有此行,打印的结果是 a b,否则打印的结果是b b // fmt.Println(s1, "===", s2) fmt.Println(string(s1), string(s2)) }...
-
Map 在 Go runtime 中的高效实现(不使用范型)
这篇文章基于我在日本东京 [GoCon Spring 2018](https://gocon.connpass.com/event/82515/) 上的演讲讨论了,Go 语言中的 map 是如何实现的。 ## 什么是映射函数 要明白 map 是如何工作的的,我们需要先讨论一下 *map 函数*。一个 map 函数用以将一个值映射到另一个值。给定一个值,我们叫 *key*,它就会返回另外一个值,称为 *value*。 ``` map(key) → value ``` 现...
-
Go语言反射规则 - The Laws of Reflection
Go语言反射规则 - The Laws of Reflection 原文地址:http://blog.golang.org/laws-of-reflection 介绍 反射在计算机的概念里是指一段程序审查自身结构的能力,主要通过类型进行审查。它是元编程的一种形式,同样也是引起混乱的重大来源。 在这篇文章里我们试图阐明Go语言中的反射是如何工作的。每种语言的反射模型是不同的(许多语言不支持反射),然而本文只与Go有关,所以我们接下来所提到的“反射”都是指Go语言中的反射。 类型与接口 由于反射是建...
-
深入解析 Go 中 Slice 底层实现
切片是 Go 中的一种基本的数据结构,使用这种结构可以用来管理数据集合。切片的设计想法是由动态数组概念而来,为了开发者可以更加方便的使一个数据结构可以自动增加和减少。但是切片本身并不是动态数据或者数组指针。切片常见的操作有 reslice、append、copy。与此同时,切片还具有可索引,可迭代的优秀特性。 一. 切片和数组 关于切片和数组怎么选择?接下来好好讨论讨论这个问题。 在 Go 中,与 C 数组变量隐式作为指针使用不同,Go 数组是值类型,赋值和函数传参操作都会复制整个数组数据。 f...
-
Go 语言汇编快速入门
在 Go 的源码中包含大量汇编语句,最优秀的示例代码位于 `math/big`, `runtime` 和 `crypto` 这些库中,但是从这里入门的话实在太过于痛苦,这些示例都是着力于系统操作和性能的运行代码。 对于没有经验的 Go 语言爱好者来说,这样会使通过库代码的学习过程遇到很大困难 。这也是撰写本文的原因所在。 Go ASM ( 译者注:ASM 是汇编的简写 ) 是一种被 Go 编译器使用的特殊形式的汇编语言,而且它基于 Plan 9 (译者注:来自贝尔实验室的概念[网络操...
-
Go 执行追踪器(execution tracer)
## 概述 你有没有好奇过 Go 运行时是如何调度 goroutine 的?有没有深入研究过为什么有时候加了并发但是性能没有提高? Go 提供了执行跟踪器,可以帮助你诊断性能问题(如延迟、竞争或低并发等)、解决前面那些疑问。 Go 从 1.5 版本开始有执行跟踪器这么一个工具,原理是:监听 Go 运行时的一些特定的事件,如: 1. goroutine的创建、开始和结束。 2. 阻塞/解锁goroutine的一些事件(系统调用,channel,锁) 3. 网络I/O相关事件 ...
-
Go 语言机制之内存剖析(Language Mechanics On Memory Profiling)
## 前序(Prelude) 本系列文章总共四篇,主要帮助大家理解 Go 语言中一些语法结构和其背后的设计原则,包括指针、栈、堆、逃逸分析和值/指针传递。这是第三篇,主要介绍堆和逃逸分析。(译者注:这一篇可看成第二篇的进阶版) 以下是本系列文章的索引: 1. [Go 语言机制之栈与指针](https://studygolang.com/articles/12443) 2. [Go 语言机制之逃逸分析](https://studygolang.com/articles/12444...
-
Go 语言机制之逃逸分析(Language Mechanics On Escape Analysis)
## 前序(Prelude) 本系列文章总共四篇,主要帮助大家理解 Go 语言中一些语法结构和其背后的设计原则,包括指针、栈、堆、逃逸分析和值/指针传递。这是第二篇,主要介绍堆和逃逸分析。 以下是本系列文章的索引: 1. [Go 语言机制之栈与指针](https://studygolang.com/articles/12443) 2. [Go 语言机制之逃逸分析](https://studygolang.com/articles/12444) 3. [Go 语言机制之内存剖析]...
-
Go 语言机制之栈和指针
## 前言 本系列文章总共包括 4 篇,主要帮助大家理解 Go 语言中一些语言机制和其背后的设计原则,包括指针、栈、堆、逃逸分析和值传递/地址传递。这一篇是本系列的第一篇,主要介绍栈和指针。 以下是本系列文章的索引: 1. [Go 语言机制之栈与指针](https://studygolang.com/articles/12443) 2. [Go 语言机制之逃逸分析](https://studygolang.com/articles/12444) 3. [Go 语言机制之内存剖析...
-
golang: 详解interface和nil
golang的nil在概念上和其它语言的null、None、nil、NULL一样,都指代零值或空值。nil是预先说明的标识符,也即通常意义上的关键字。在golang中,nil只能赋值给指针、channel、func、interface、map或slice类型的变量。如果未遵循这个规则,则会引发panic。对此官方有明确的说明:http://pkg.golang.org/pkg/builtin/#Type golang中的interface类似于java的interface、PHP的inte...
-
Go Select的实现
select语法总结 select对应的每个case如果有已经准备好的case 则进行chan读写操作;若没有则执行defualt语句;若都没有则阻塞当前goroutine,直到某个chan准备好可读或可写,完成对应的case后退出。 Select的内存布局了解chanel的实现后对select的语法有个疑问,select如何实现多路复用的,为什么没有在第一个channel操作时阻塞 从而导致后面的case都执行不了。为了解决疑问,对应代码看一下汇编调用了哪些runtime层的函数,发现sele...
-
Go Channel的实现
channel作为goroutine间通信和同步的重要途径,是Go runtime层实现CSP并发模型重要的成员。在不理解底层实现时,经常在使用中对channe相关语法的表现感到疑惑,尤其是select case的行为。因此在了解channel的应用前先看一眼channel的实现。 Channel内存布局channel是go的内置类型,它可以被存储到变量中,可以作为函数的参数或返回值,它在runtime层对应的数据结构式hchan。hchan维护了两个链表,recvq是因读这个chan而阻塞的G...
-
Go 调优技术
## 内存管理 在开始探索 Go 调优技术和工具之前,我们需要先了解一下 Go 内存模型,它可以帮助我们理解内存是如何使用的。 Go 实现的是 _并行的_ [标记-清除垃圾回收器](http://wiki.c2.com/?MarkAndSweep)。在 _传统的_ 标记-清除模型中,垃圾回收器会先让程序停下来(也就是,“stop the world”),然后查找已经失效的对象,并把这些对象清理掉(也就是,释放内存)。因为程序在运行中会移动引用(references),导致垃圾的识别和...
-
使用 pprof 和火焰图调试 golang 应用
什么是 Profiling? Profiling 这个词比较难翻译,一般译成画像。比如在案件侦破的时候会对嫌疑人做画像,从犯罪现场的种种证据,找到嫌疑人的各种特征,方便对嫌疑人进行排查;还有就是互联网公司会对用户信息做画像,通过了解用户各个属性(年龄、性别、消费能力等),方便为用户推荐内容或者广告。 在计算机性能调试领域里,profiling 就是对应用的画像,这里画像就是应用使用 CPU 和内存的情况。也就是说应用使用了多少 CPU 资源?都是哪些部分在使用?每个函数使用的比例是多少?有哪些函...
-
记一次获得3倍性能的go程序优化实践,及on-cpu/off-cpu火焰图的使用
先把结论列在前面: Golang的性能可以做到非常好,但是一些native包的性能很可能会拖后腿,比如regexp和encoding/json。如果在性能要求较高的场合使用,要根据实际情况做相应优化。 on-cpu/off-cpu火焰图的使用是程序性能分析的利器,往往一针见血。虽然生成一张火焰图比较繁琐(尤其是off-cpu图),但绝对值得拥有! 之前一直使用Logstash作为日志文件采集客户端程序。Logstash功能强大,有丰富的数据处理插件及很好的扩展能力,但由于使用JRuby实现,性能...
-
也谈goroutine调度器
Go语言在2016年再次拿下TIBOE年度编程语言称号,这充分证明了Go语言这几年在全世界范围内的受欢迎程度。如果要对世界范围内的gopher发起一次“你究竟喜欢Go的哪一点”的调查,我相信很多Gopher会提到:goroutine。 Goroutine是Go语言原生支持并发的具体实现,你的Go代码都无一例外地跑在goroutine中。你可以启动许多甚至成千上万的goroutine,Go的runtime负责对goroutine进行管理。所谓的管理就是“调度”,粗糙地说调度就是决定何时哪个goro...
-
Goroutine浅析
CSAPP ch12总结了三种并发模型:基于进程,基于IO多路复用,基于线程。在实际的服务器应用中基于线程的并发模型并不能创建和使用过多的thread。因为thread数目过多于CPU核数,内核调度和切换thread将付出较大代价。因此通常在基于线程的基础上,在用户态设计用户态线程模型与调度器,使得调度不需要陷入内核完成,减小并发调度代价。 调度器的设计与演化用户态线程模型又根据多少个协程对应OS内核线程区分为1:1 M:1 M:N 三种。go在runtime层实现的是M:N的用户态线程+调度器...
-
深入理解Go 1.9 sync.Map
Go官方的faq已经提到内建的map不是线程(goroutine)安全的。在Go 1.6之前, 内置的map类型是部分goroutine安全的,并发的读没有问题,并发的写可能有问题。自go 1.6之后, 并发地读写map会报错,这在一些知名的开源库中都存在这个问题,所以go 1.9之前的解决方案是额外绑定一个锁,封装成一个新的struct或者单独使用锁都可以。另外笔者在go 1.9之前通常是使用concurrent-map来解决这类问题,但是不是所有的第三方库都以此来解决问题。 我们先来看看这个...
-
Go 反射与interface拾遗
Go能实现接口的动态性和反射的基础是:编译期为运行时提供了类型信息。interface底层有两种结构,上一节讲了带方法的iface,这一节补充不带方法的eface结构。 interface之efaceGo中的任何对象都可以表示为interface{}。它扮演的角色与C中的void*差不多,区别在于interface{}中包含有类型信息,可以实现反射。 efece数据结构描述:gcdata域用于垃圾回收,size描述类型的大小,hash表示数据的hash值,align是对齐,fieldalign是...
-
Go 方法调用与接口
在比较C++和Go的时候,通常会说到Go不支持继承和多态,但通过组合和接口实现了类似的语言特性。总结一下Go不支持的原因:(1) 首先struct是值类型,赋值和传参都会复制全部内容。struct的内存布局跟C几乎一致,没有任何附加的object信息,比如指向虚函数表的指针。(2)其次Go不支持隐式的类型转换,因此用基类的指针指向子类会编译错误。 Go程序抽象的基本原则依赖于接口而不是实现,优先使用组合而不是继承。 struct的方法调用对象的方法调用相当于普通函数调用的语法糖。Value方法的...
-
Go 函数调用惯例
对比C++,Go不支持重载和默认参数,支持不定长变参,多返回值,匿名函数和闭包。 C入栈顺序和返回值之前有个疑问,为什么Go支持多返回值,而C不行呢。首先回顾一下C函数调用时的栈空间 程序员的自我修养Ch10-2。函数调用时首先参数和返回地址入栈,其次入栈old ebp和需要保存的寄存器,之后是函数内部的局部变量和其他数据。两个指针ebp和esp分别指向返回地址和栈顶。 函数返回值的传递有多种情况。若小于4字节,返回值存入eax寄存器,由函数调用方读取eax。若返回值5到8字节,采用eax和ed...