Ryo's blog

分类 · Language

首页

关于

归档

loading..
GolangCompiler

Golang 编译器优化那些事

一、背景去年写了一篇 Golang Memory Model 文章。当时在文章里面贴了验证一个线程可见性问题Demo,具体代码如下: func main() { running := true go func() { println("start thread1") count := 1 for running { count++ } println("end thread1: count =", count) // 这句代码永远执行不到为什么? }() go func() { println("start thread2") for..

更多
loading..
Golang

Golang Memory Model

一、背景1.1 一个 Code Review 引发的思考一个同学在 Golang 项目里面用 Double Check(不清楚的同学可以去百度搜下,Java中比较常见)的方式实现了一个单例。具体实现如下: var ( lock sync.Mutex instance *UserInfo ) func getInstance() (*UserInfo, error) { if instance == nil { //---Lock lock.Lock() defer lock.Unlock() if instance == nil { instance = &UserInfo{..

更多
loading..
ChatRoom

《基于 Rust 实现一个加密的 IM 聊天室》

一、背景最近在看Rust相关的东西,想找个项目用Rust练下手,熟悉一下Rust基本特性。然后聊天工具是我们日常最常用的一个软件,我一直想自己写个安全的聊天软件(程序员一般都不相信非开源的程序)。 最终实现的效果图如下(项目地址): 二、技术选型说到IM软件,我们常常就会想到一些特性,比如实时性、安全性、可靠性、跨平台兼容性、消息有序等等,我们看下常见的一些IM的技术方案有哪些。 2.1 HTTP 轮询Http 轮询顾名思义,通过不停轮询的方式来判断是否有收到新的消息。轮询还分为长轮询和短轮询两种。 短轮询(Short Polling): 短轮询是客户端定期向服务器发送请求,查询是否有新数据。通常,客户端会在每个请求之间设置一个固定时间间隔。以下是短轮询的基本工作流程: 客户端向服务器发送HTTP请..

更多
Golang

深入理解 Golang Stack

一、基础知识1.1 Linux 虚拟地址空间布局我们知道CPU有实模式和保护模式,系统刚刚启动的时候是运行在实模式下,然后经过一系列初始化工作以后,Linux会把CPU的实模式改为保护模式(具体就是修改CPU的CR0寄存器相关标记位),在保护模式下,CPU访问的地址都是虚拟地址(逻辑地址)。Linux 为了每个进程维护了一个单独的虚拟地址空间,虚拟地址空间又分为“用户空间”和“内核空间”。 虚拟地址空间更多相关可以看Linux内核虚拟地址空间这篇文章。 1.2 Golang 栈和虚拟地址空间栈的区别Golang 的内存管理是用的 TCMalloc(Thread-Caching Malloc)算法, 简单点说就是 Golang 是使用 mmap 函数去操作系统申请一大块内存,然后把内存按照 ..

更多
ele

Golang基础

其他 Golang 相关技术沉淀文章 Golang Memory Model Golang 编译器优化那些事 深入理解 Golang Stack Golang “锁”事 Golang Context 详解 Go 泛型初窥 Go源码——Sync.Mutex Go源码——runtime.semaphore Go源码——runtime.mutex Go源码——Sync.Map的前生今世 GO非类型安全指针-Unsafe.Pointer Go 自定义引用包的域名 一次线上内存使用率异常问题排查 Go for-range 的奇技淫巧 Golang RWMutext 代码走读 Golang 内存对齐问题 Golang基础 - 脑图链接

更多
BookRust

《Rust 编程第一课》

《陈天 · Rust 编程第一课》 一、所有权 脑图链接 所有权和生命周期是Rust和其它编程语言的主要区别,也是Rust其它知识点的基础。 1.1、变量在函数调用时发生了什么fn main() { // vec 动态数组因为大小在编译期无法确定,所以放在堆上, // 并且在栈上有一个包含了长度和容量的胖指针指向堆上的内存。 let data = vec![10, 42, 9, 8]; let v = 42; if let Some(pos) = find_pos(data, v) { println!("Found {} at {}", v, pos); } } fn find_pos(data: Vec<u32>, v: ..

更多
Golang

Golang “锁”事

一、 Go 同步原语 sync.Cond -> notifyList -> runtime.mutex、atomic sync.WaitGroup -> atomic、 runtime.sema sync.Map -> sync.Mutex、atomic sync.Once -> sync.Mutex、atomic sync.RWMutex -> sync.Mutex、atomic sync.Mutex -> runtime.sema channel -> runtime.mutex sync.Mutex和runtime.mutext区别:简单说就是sync.Mutex是用户层的锁,Lock抢锁失败会造成goroutine阻塞(会调用gopark)。run..

更多
Golang

Golang Context 详解

基于 Go 1.18 源码分析 一、引言1.1 什么是 Context?Context是Go 1.7引入的一个标准库,官方 blog 里面介绍,最早是Google内部使用的一个库,主要用于在一个Request对应的多个Goroutine中传递数据,数据主要分为两种: 请求的基本信息,比如用户鉴权信息、请求的Request-ID等等。 请求的Deadline,如果请求被Cancel或者Timeout,能够控制多个Goroutine会返回。 整个 context.go 加上注释也就600行左右。核心就是Context type : type Context interface { // 获取 DeadLine 时间,使用 WithDeadline 和 WithTimeout 才有 Deadl..

更多
BookRust

《Hello Rust Async》

摘录与 Asynchronous Programming in Rust 一、Getting Started1.1 Rust 的异步 vs 其他语言的尽管很多语言都支持异步编程,但实现细节上有很多不一样。Rust的异步实现和大部分语言的在以下方面有区别: Rust中 Futures 是惰性的,并且只有被轮询才会进一步执行。丢弃(Dropping)一个future可以阻止它继续执行。 Rust中的异步是零成本的,这意味着你只需要为你所使用的东西付出代价。特别来说,你使用异步时可以不需要堆分配或动态分发,这对性能来说是好事!这也使得你能够在约束环境下使用异步,例如嵌入式系统。 Rust不提供内置运行时。相反,运行时由社区维护的库提供。 Rust里单线程的和多线程的运行时都可用,而他们会有不同的优劣。 Dem..

更多
Rust

《Hello Rust》

摘录于 Rust 程序设计语言 中文版 零、Why Rust Rust 是一种令人兴奋的新编程语言,它可以让每个人编写可靠且高效的软件。 它可以用来替换C/C++,Rust和他们具有同样的性能,但是很多常见的bug在编译时就可以被消灭。 Rust是一种通用的编程语言,但是他更善于以下场景: 需要运行时的速度 需要内存安全 更好的利用多处理器 Rust安全、无需GC、易于维护、调试、代码安全高效。 Rust优点,性能、安全、无所畏惧的并发。 Rust特别擅长的领域 高性能的 Web Service WebAssembly 命令行工具 网络编程 嵌入式设备 系统编程 Google:新操作系统Fuschia,其中Rust代码量大约占30% Amazon:基于Linux开发的直接可以在裸机、虚拟机上运行容..

更多
Golang

Go 泛型初窥

一、基础知识1.1 形参和实参func min(a, b int) int { if a > b { return b } return a } func main() { minNum := min(100, 200) } 如上a、b叫形参(parameter),100和200叫实参(argument)。 1.2 类型形参、类型实参、类型约束、类型形参列表func sumNum[T int32 | float32](n []T) T { var s T for _, item := range n { s += item } return s } func main() { data1 :=..

更多
GolangGoSourceCode

Go源码——Sync.Mutex

一、背景sync.Mutex是我们常用到的一把锁。网上讲这个锁的文章也比较多,这里面主要是为了简单做个自我总结。 Sync.Mutex 慢路径底层依赖的是runtime_SemacquireMutex和runtime_Semrelease,对这个不了解可以先去看下 runtime.semaphore 。 二、Sync.Mutex 源码2.1 发展历史sync.Mutex第一版 代码 是2008年的时候 @rsc 提交的。最早的实现比较简单,是通过简单的CAS加信号量的方式来实现的。信号量具体可以参考 runtime-sema 这篇文章。 @dvyukov 2011年的时候,提交了第一次优化了 sync: improve Mutex to allow successive acquisitions,这一版中加..

更多
GolangGoSourceCode

Go源码——runtime.semaphore

一、背景sync.Mutex里面用了runtime_SemacquireMutex和runtime_Semrelease,所以看下这个runtime的信号量是如何实现的。 二、基础知识2.1 信号量信号量(英语:semaphore)又称为信号标,是一个同步对象,用于保持在0至指定最大值之间的一个计数值。当线程完成一次对该semaphore对象的等待(wait)时,该计数值减一;当线程完成一次对semaphore对象的释放(release)时,计数值加一。当计数值为0,则线程等待该semaphore对象不再能成功直至该semaphore对象变成signaled状态。semaphore对象的计数值大于0,为signaled状态;计数值等于0,为nonsignaled状态。 信号量的概念是由荷兰计算机科学家艾兹赫..

更多
GolangGoSourceCode

Go源码——runtime.mutex

一、背景在Go的runtime包中封装了一个 mutux ,这个mutex被runtime包中大量组件使用,比如 channel、netpoll、检查活跃的定时器 等等。 sync.Mutex和runtime.mutext区别:简单说就是sync.Mutex是用户层的锁,Lock抢锁失败会造成goroutine阻塞(会调用gopark)。runtime.mutex 是给 runtime使用的锁,Lock抢锁失败,会造成m阻塞(线程阻塞,底层调用的futex)。 二、基础知识2.1 MutexMutex 全称是Mutual Exclusion ,俗称互斥体或者互斥锁。是一种用于多线程编程中,防止两条线程同时对同一公共资源(比如全局变量)进行读写的机制。 2.2 mmap 函数mmap它的主要功能是将一个虚拟内..

更多
GolangGoSourceCode

Go源码——Sync.Map的前生今世

一、背景前段时间有个朋友来问我Go的Sync.Map性能怎么样,一般什么场景推荐使用。一句话介绍的话,就是Sync.Map底层有两个map,一个是read,一个是dirty,读写read中数据不需要加锁,读写dirty不用需要加锁,适用于读多写少的场景。 碎碎念其实2020年的时候Go源码里面一些比较常用的包都大致看了一遍,当时跟槊槊、大飞哥、周老板空闲时间天天讨论各种技术细节,包括但不仅限于操作系统、MySQL、Redis、分布式、Go、项目架构方法论等。很多时候观点不合还会争的面红耳赤,最后还会上升到人生攻击,你不服我,我也不服你(实际上互有对错,我也被打过几次脸)。因为有的东西,网上有很多错误的资料,导致我养成了一个习惯,找资料的时候我一般都是去看一些权威的技术书或者直接去看开源组件源码,能用代码说的..

更多
Golang

GO非类型安全指针-Unsafe.Pointer

一、背景朋友发了一段测试代码里面不正确的使用了atomic.StorePointer,导致GC的时候程序Panic了。 var current int64 atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&current)), unsafe.Pointer(&latest)) 为什么会Panic这里先按下不表。之前对 unsafe.Pointer 用的并不多,也没有系统了解过。所以就想系统看下。看了下 unsafe.Pointer 官方文档还挺详细的,可能只之前使用出错的人太多了,所以 rsc 单独提了一个 CR 来说明unsafe.Pointer的用法。 二、unsafe.Pointerunsafe.Pointer表示指向任意类型..

更多
Golang

Go 自定义引用包的域名

一、 背景最近在看 Go源码的时候,发下部分库最早是在 x-pkg 里面的,经过一段时间迭代才进了runtime包里面。 x-pkg 里面介绍了用途和源码地址。 golang.org/x 文档 我发现 x-pkg 的源码地址都在 https://go.googlesource.com, 但是我们项目里面导入某个x-pkg库的路径确是 import "golang.org/x/sync/semaphore" 比较好奇,这import的别名是在哪里做的,感觉是个挺冷门的知识,于是搜了下相关资料。 二、实现步骤找到了官网相关资料: hdr-Remote_import_paths 简单说就是在你的网址里面加入如下信息。 <meta name="go-import" content="example.or..

更多
Golang

一次线上内存使用率异常问题排查

一、背景朋友的一个服务,某个集群内存的RSS使用率一直在80%左右,他用的是8核16G, 双机房一共206个实例。 但是在pprof里面查的堆内存才使用了6.3G左右,程序里面主要用了6G的LocalCache所以heap用了6.3G是符合预期的。 朋友让我帮忙看下,额外的内存到底是被啥占用了。 二、基础知识2.1 TCMalloc 算法Thread-Caching Malloc 是Google开发的内存分配算法库,最开始它是作为Google的一个性能工具库perftools的一部分。 TCMalloc是用来替代传统的malloc内存分配函数。它有减少内存碎片,适用于多核,更好的并行性支持等特性。 2.2 mmap 函数mmap它的主要功能是将一个虚拟内存区域与一个磁盘上的文件关联起来,以初始化这个虚..

更多
Golang

Go for-range 的奇技淫巧

背景朋友发了两个代码片段给我看,让我猜输出的内容是啥。具体代码如下: // Demo1 // 1. 这个循环是否能停下来? // 2. 如果能停下来,打印的 arr 内容是什么? arr := []int{1, 2, 3} for _, v := range arr { arr = append(arr, v) } fmt.Println(arr) // Demo2 // 1. idx 和 value 输出多少? // 2. 输出几行? str := "你好" for idx, v := range str { fmt.Printf("idx = %d , value = %c\n", idx, v) } 不卖关子,先说下第一个Demo输出的是: [1 2 3 1 2 3] 第二..

更多
Golang

Golang RWMutext 代码走读

type RWMutex struct { w Mutex // held if there are pending writers writerSem uint32 // 写的信号量 readerSem uint32 // 读的信号量 readerCount int32 // 等待写的个数 readerWait int32 // 等待读的个数 } // 加“读锁” // 对readerCount + 1 。 // 然后看 readerCount是不是小于0 // 小于0表示 正在加写锁,然后阻塞到rw.readerSem 这个信号上。 func (rw *RWMutex) RLock() { if atomic.AddInt32(..

更多
Golang

Golang 内存对齐问题

什么是内存对齐?CPU把内存当成是一块一块的,块的大小可以是2,4,8,16字节大小,因此CPU在读取内存时是一块一块进行读取的。块大小成为memory access granularity(粒度)。 假设CPU访问粒度是4,也就是一次性可以读取内存中的四个字节内容;当我们不采用内存对齐策略,如果需要访问A中的b元素,CPU需要先取出0-3四个字节的内容,发现没有读取完,还需要再次读取,一共需要进行两次访问内存的操作;而有了内存对齐,参考左图,可一次性取出4-7四个字节的元素也即是b,这样就只需要进行一次访问内存的操作。所以操作系统这样做的原因也就是所谓的拿空间换时间,提高效率。 为什么要内存对齐?会了关于结构体内存大小的计算,可是为什么系统要对于结构体数据进行内存对齐呢,很明显所占用的空间大小要更多。原..

更多
GolangLua

Go 执行Lua脚本和JS脚本测试

最近有个需求需要在Go项目里面执行动态脚本,github上有好几个lua执行解释器,但是有很多要不就很久没维护了,要不就没有什么文档,经过几个对比我最后用的是 https://github.com/yuin/gopher-lua。JS解析器用的github.com/robertkrimen/otto。 具体测试代码如下,给有需求的朋友参考。 github地址 package main import ( "fmt" "github.com/robertkrimen/otto" "github.com/yuin/gluamapper" "github.com/yuin/gopher-lua" "time" ) //function add(a, b) //return..

更多