From 26c14bbc9d13299626acd9f14549fbdd0d0be9d5 Mon Sep 17 00:00:00 2001 From: asahi Date: Sat, 11 Jan 2025 16:17:27 +0800 Subject: [PATCH] =?UTF-8?q?=E9=98=85=E8=AF=BBgolang=20sync.Once=E6=96=87?= =?UTF-8?q?=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Golang/Golang Document.md | 101 +++++++++++++++++++++++++++++++++++++- 1 file changed, 99 insertions(+), 2 deletions(-) diff --git a/Golang/Golang Document.md b/Golang/Golang Document.md index 14b9a99..10ed0a7 100644 --- a/Golang/Golang Document.md +++ b/Golang/Golang Document.md @@ -1,3 +1,46 @@ +- [Golang](#golang) + - [Get Started](#get-started) + - [Enable dependency tracking](#enable-dependency-tracking) + - [go mod init](#go-mod-init) + - [go mod tidy](#go-mod-tidy) + - [multi-module workspace](#multi-module-workspace) + - [go work init](#go-work-init) + - [go work use](#go-work-use) + - [Gin框架构建restful api](#gin框架构建restful-api) + - [向response中写入返回数据](#向response中写入返回数据) + - [解析request中的数据](#解析request中的数据) + - [将请求的endpoint注册到server中](#将请求的endpoint注册到server中) + - [golang generic](#golang-generic) + - [不使用泛型的代码编写](#不使用泛型的代码编写) + - [使用泛型的代码编写](#使用泛型的代码编写) + - [comparable](#comparable) + - [泛型方法调用](#泛型方法调用) + - [type constraint](#type-constraint) + - [Fuzzing](#fuzzing) + - [unit test编写](#unit-test编写) + - [fuzz test编写](#fuzz-test编写) + - [执行fuzz test](#执行fuzz-test) + - [sync.Pool](#syncpool) + - [sync.Pool使用示例](#syncpool使用示例) + - [Pool和垃圾回收](#pool和垃圾回收) + - [poolCleanup](#poolcleanup) + - [allPools \& oldPools](#allpools--oldpools) + - [Proc Pining](#proc-pining) + - [per-P](#per-p) + - [local \& localSize](#local--localsize) + - [PinSlow](#pinslow) + - [Pool Local](#pool-local) + - [pool的Put/Get](#pool的putget) + - [Put](#put) + - [Get](#get) + - [slow path](#slow-path) + - [Sync.once](#synconce) + - [use case](#use-case) + - [syntax](#syntax) + - [iota](#iota) + + + # Golang ## Get Started ### Enable dependency tracking @@ -310,8 +353,7 @@ ok git.kazusa.red/asahi/fuzz-demo 10.360s > #### new interesting > `new interesting`指会扩充code coverage的用例输入,在fuzz test刚开始时,new interesting数量通常会因发现新的代码路径快速增加,然后,会随着时间的推移逐渐减少 -## Go Sync -### sync.Pool +## sync.Pool `sync.Pool`为golang标准库中的实现,用于降低allocation和减少垃圾回收。 ### sync.Pool使用示例 @@ -708,6 +750,61 @@ func (p *Pool) getSlow(pid int) any { - 如果所有victim中的poolLocal对象都返回为空,那么会将victim中`p.victimSize`标识为空,后续再次执行slow path时,如果感知到victimSize为空,那么便不会再次查找victim +## Sync.once +sync.Once是golang中提供的工具包,确保指定的代码块在并发环境下只会被执行一次。 + +sync.Once为struct,其中只包含一个方法`Do(f func())`。sync.Once保证指定方法只会被执行一次,即使在多routine环境下被调用了多次。`并且,sync.Once方法是线程安全的`。 + +### use case +sync.Once的用例如下: +- 对共享的资源进行初始化 +- 设置单例 +- 执行只需要运行一次的高开销计算 +- 导入配置文件 + +sync.Once的使用示例如下: +```go +var instance *singleton +var once sync.Once + +func getInstance() *singleton { + once.Do(func() { + instance = &singleton{} + }) + return instance +} +``` + +sync.Once实现逻辑如下: +```go +type Once struct { + // done indicates whether the action has been performed. + // It is first in the struct because it is used in the hot path. + // The hot path is inlined at every call site. + // Placing done first allows more compact instructions on some architectures (amd64/386), + // and fewer instructions (to calculate offset) on other architectures. + done atomic.Uint32 + m Mutex +} + +func (o *Once) Do(f func()) { + + if o.done.Load() == 0 { + // Outlined slow-path to allow inlining of the fast-path. + o.doSlow(f) + } +} + +func (o *Once) doSlow(f func()) { + o.m.Lock() + defer o.m.Unlock() + if o.done.Load() == 0 { + defer o.done.Store(1) + f() + } +} +``` + ## syntax ### iota `iota`关键字代表连续的整数变量,`0, 1, 2`,每当`const`关键字出现时,其重置为0