go 开发小技巧

一、简介

       本篇文章会介绍go 开发小技巧。

二、go 开发技巧

2.1 Semaphore
type Semaphore chan struct{}func NewSemaphore(maxCount int) Semaphore {return make(chan struct{}, maxCount)
}func (s Semaphore) Acquire() {s <- struct{}{}
}func (s Semaphore) tryAcquire() bool{select {case s <- struct{}{}:default:return false}return true
}func (s Semaphore) Release() {<-s
}
2.2 singleflight

    有点类似react的useMemo hook,会缓存函数结果


type SingleFlight struct {m map[string]*call
}type call struct {sync.Onceres any
}func newSingleFlight() *SingleFlight {return &SingleFlight{m: make(map[string]*call),}
}func (sf *SingleFlight) Do(key string, fn func() (any, error)) (any, error) {if sf.m[key] != nil {return sf.m[key].res, nil}ca := &call{}var err errorca.Once.Do(func() {if res, e := fn(); e == nil {ca.res = reserr = esf.m[key] = ca}})return ca.res, err
}
demo
func main() {var sf = newSingleFlight()var wg sync.WaitGroupvar t = time.Now()for i := 0; i < 10; i++ {wg.Add(1)go func() {res, _ := sf.Do("longFunc", func() (any, error) {time.Sleep(5 * time.Second)return 5, nil})fmt.Println(res)wg.Done()}()}wg.Wait()fmt.Println(time.Since(t))
}
2.3 once

    once 可以用来处理只需要之心一次的结果

var (once     sync.Onceinstance *Config
)func GetConfig() *Config {once.Do(func() {instance = loadConfig()})return instance
}
2.4 error group

   err group 可以在调用线程获取并发执行goroute 的错误

func main() {urls := []string {"https://blog.devtrovert.com","https://example.com",}var g errgroup.Groupfor _, url := range urls {url := url // safe before Go 1.22g.Go(func() error {return fetch(url)})}if err := g.Wait() ; err != nil {log.Fatal(err)}
}
2.5 Pool 

Pool是对象池,可以复用对象

type Pool[T any] struct {internal sync.Pool
}func NewPool[T any](newF func() T) *Pool[T] {return &Pool[T]{internal: sync.Pool{New: func() interface{} {return newF()},},}
}func (p *Pool[T]) Get() T {return p.internal.Get().(T)
}func (p *Pool[T]) Put(v T) {p.internal.Put(v)
}
2.6 error

 1. 自定义error的粒度是类型,例如参数类型错误,可重试错误。

  2.wrap或join。

func readConfig(path string) error {return fmt.Errorf("read config: %w", ErrNotFound)
}func main() {err := readConfig("config.json")if errors.Is(err, ErrNotFound) {fmt.Println("config file not found")}
}

  

func main() {var errs = make([]error, 30)var g sync.WaitGroupfor i := 0; i < 10; i++ {g.Add(1)j := igo func(i int) {errs = append(errs, errors.New(fmt.Sprintf("hello, %d", i)))defer g.Done()}(j)}g.Wait()fmt.Println(errors.Join(errs...))
}

join 将多个错误连接

2.7 defer 
测量函数执行时间
func main() {defer TrackTime(time.Now()) // <--- THIStime.Sleep(500 * time.Millisecond)
}func TrackTime(pre time.Time) time.Duration {elapsed := time.Since(pre)fmt.Println("elapsed:", elapsed)return elapsed
}// elapsed: 501.11125ms
2.8 实现接口判断

interface

type Buffer interface {Write(p []byte) (n int, err error)
}type StringBuffer struct{}

判断StringBuffer 是否实现Buffer

// syntax: var _ <interface> = (*type)(nil)
var _ Buffer = (*StringBuffer)(nil)
2.9 worker pool
package tasksimport "sync"type Worker struct {maxWorker intch        chan func()wg        sync.WaitGroupresMap    map[string]chan any
}func NewWorker(maxWorker int) *Worker {w := &Worker{maxWorker: maxWorker,ch:        make(chan func()),resMap:    make(map[string]chan any),}for i := 0; i < maxWorker; i++ {go func() {for f := range w.ch {w.done(f)}}()}return w
}func (w *Worker) Go(f func()) {w.wg.Add(1)w.ch <- f
}func (w *Worker) Wait() {w.wg.Wait()close(w.ch) // 关闭通道
}func (w *Worker) done(f func()) {defer w.wg.Done()f()
}func (w *Worker) submit(f func() (res any), key string) chan any {w.resMap[key] = make(chan any)funcWrapper := func() {var res = f()w.resMap[key] <- resclose(w.resMap[key] // 关闭通道}w.Go(funcWrapper)return w.resMap[key]
}
2.10 ConcurrentMap
type ConcurrentMap struct {innerMap map[string]anyrwLock   sync.RWMutex
}func (currMap *ConcurrentMap) Get(key string) any {currMap.rwLock.RLock()defer currMap.rwLock.RUnlock()return currMap.innerMap[key]
}func (currMap *ConcurrentMap) Put(key string, value any) {currMap.rwLock.Lock()defer currMap.rwLock.Unlock()currMap.innerMap[key] = value
}func (currMap *ConcurrentMap) PutIfAbsent(key string, supplier func() any) {currMap.rwLock.Lock()defer currMap.rwLock.Unlock()if value := currMap.innerMap[key]; value != nil {return}currMap.innerMap[key] = supplier()
}
func NewCurrMap() *ConcurrentMap {return &ConcurrentMap{innerMap: make(map[string]any),}
}func (currMap *ConcurrentMap) getOrDefault(key string, supplier func() any) any {currMap.rwLock.RLock()defer currMap.rwLock.RUnlock()if value := currMap.innerMap[key]; value != nil {return value}return supplier()
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/53329.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

在js渲染的dom中的事件中传递对象

在某些情况下&#xff0c;可能需要将整个对象或部分对象嵌入到 HTML 元素的属性中&#xff0c;可以将对象数据序列化为 JSON 字符串&#xff0c;存储在 data-* 自定义属性中。这样可以在事件中取出并解析对象数据&#xff1a; <!DOCTYPE html> <html lang"en&qu…

linux高级学习9

24.9.6学习目录 一.共享内存1.共享内存的API 一.共享内存 特点&#xff1a; 其在进程间共享数据的方法中是最快的要注意对给定存储区访问时进行互斥 1.共享内存的API &#xff08;1&#xff09;获取共享内存标识符 在shell中使用 ipcs -m进行查看共享内存 ipcrm -m shmid删…

P1546 [USACO3.1] 最短网络 Agri-Net

[题目通道]([USACO3.1] 最短网络 Agri-Net - 洛谷) #include<bits/stdc.h> #define int long long using namespace std; const int N1e6100; struct edge{int u,v,w; }e[N*30]; bool cmp(edge a,edge b){return a.w<b.w; } int a,b,c,n,m,fa[N],cnt0,ans0; int fin…

目标检测-YOLOv10

YOLOv10 是 YOLO 系列的最新版本&#xff0c;进一步推动了目标检测技术的发展。它在前代&#xff08;YOLOv9&#xff09;的基础上进行了更多优化和改进&#xff0c;使得模型在复杂场景、实时性以及精度方面取得了更高的突破。YOLOv10 将高效的架构设计与新颖的技术结合&#xf…

C++万字解读类和对象(上)

1.类的定义 class为定义类的关键字&#xff0c;Stack为类的名字&#xff0c;{}中为类的主体&#xff0c;注意类定义结束时后面分号不能省略。类体中内容称为类的成员&#xff1a;类中的变量称为类的属性或成员变量; 类中的函数称为类的方法或者成员函数。 为了区分成员变量&…

[QT] QT事件与事件重写

一.事件 事件(event)是由系统或者 Qt本身在不同的场景下发出的。当用户按下鼠标、敲下键盘&#xff0c;或者是窗口关闭等都会发出一个相应的事件。 一些事件在用户操作时发出(如鼠标/键盘事件); 另一些事件则是由系统自动发出(如计时器事件)。 Qt窗口中对于产生的一系列事件都…

MarkdownEditor 配置以及使用

MarkdownEditor 配置以及使用 MarkdownEditor是一款基于浏览器的 Markdown 编辑器&#xff0c;虽然他是独立软件&#xff0c;但该软件内嵌一个浏览器。功能非常简单实用、反应速度很快&#xff0c;号称是Markdown领域的NotePad&#xff08;记事本&#xff09;。 MarkdownEdit…

PHP与Nginx配置优化:深入探讨Socket通信

在现代Web开发中&#xff0c;PHP和Nginx的组合是一种常见且高效的服务器配置。本文将深入探讨PHP-FPM&#xff08;FastCGI进程管理器&#xff09;与Nginx的配置&#xff0c;特别是关于它们之间的通信方式——Unix Domain Socket和TCP Socket的选择与优化。 PHP-FPM配置解析 首…

计网名词解释

DNS的主要功能和特点 域名解析&#xff1a;DNS的核心功能是将用户输入的域名解析为IP地址。因为计算机之间只能通过IP地址进行通信&#xff0c;而域名更易于人类记忆和使用&#xff0c;所以DNS起到了桥梁的作用。 分布式数据库&#xff1a;DNS是一个分布式的数据库系统&#x…

Vue3 父子传参 简单易懂

在Vue 3中&#xff0c;父组件向子组件传递数据&#xff08;也称为“props”&#xff09;是一个非常常见的模式。这是通过props选项在子组件中定义的&#xff0c;然后在父组件的模板中使用该子组件时通过属性&#xff08;attributes&#xff09;传递数据。 步骤 1: 定义子组件的…

面向对象23种设计模式通俗理解

终点即是起点,自强不息! 设计模式的理解 设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。 模式&#xff1a;在某些场景下&#xff0c;针对某类问题的某种通用的解决方案。 场景&#xff1a;项目所在的环境 问题&#xff1a;约束条件&#xff0c;项目目标…

vue3 项目中使用git

一.vue项目创建 二.创建本地仓库并和远程仓库进行绑定 在vue3-project-git 项目文件夹下 初始化一个新的Git仓库&#xff0c;可以看到初始化成功之后就会出现一个.git文件&#xff0c;该文件包含所有必要的 Git 配置和版本控制信息。 创建远程仓库: 打开gitee ,点击右上角 ‘…

MapSet之二叉搜索树

系列文章&#xff1a; 1. 先导片--Map&Set之二叉搜索树 2. Map&Set之相关概念 目录 前言 1.二叉搜索树 1.1 定义 1.2 操作-查找 1.3 操作-新增 1.4 操作-删除(难点) 1.5 总体实现代码 1.6 性能分析 前言 TreeMap 和 TreeSet 是 Java 中基于搜索树实现的 M…

DELTA_IA-ASD_ASDA-A2简明教程

该文章仅供参考&#xff0c;编写人不对任何实验设备、人员及测量结果负责&#xff01;&#xff01;&#xff01; 0 引言 文章主要介绍电机的硬件连接、软件配置、转动调试以及软件控制。文章中提到的内容在产品手册中都有说明&#xff0c;强烈建议在操作前通读产品手册&#…

RocketMQ高级特性三-消费者分类

目录 前言 概述 区别 PullConsumer 定义与概述 原理机制 使用场景 优缺点 Java 代码示例 SimpleConsumer 定义与概述 原理机制 使用场景 优缺点 Java 代码示例 PushConsumer 定义与概述 原理机制 使用场景 优缺点 Java 代码示例 总结 前言 RocketMQ中的消…

【2024高教社杯全国大学生数学建模竞赛】B题 生产过程中的决策问题——解题思路 代码 论文

目录 问题 1&#xff1a;抽样检测方案的设计问题 2&#xff1a;生产过程中的决策问题 3&#xff1a;多工序、多零配件的生产决策问题 4&#xff1a;重新分析次品率题目难度分析1. 统计检测方案设计的复杂性&#xff08;问题 1&#xff09;2. 多阶段生产决策的复杂性&#xff08…

常用排序算法(上)

目录 前言&#xff1a; 1.排序的概念及其运用 1.1排序的概念 1.2排序运用 1.3 常见的排序算法 2.常见排序算法的实现 2.1 堆排序 2.1 1 向下调整算法 2.1 2 建堆 2.1 3 排序 2.2 插入排序 2.1.1基本思想&#xff1a; 2.1.2直接插入排序&#xff1a; 2.1.3 插…

SQL进阶技巧:每年在校人数统计 | 区间重叠问题

目录 0 问题分析 1 数据准备 2 问题分析 3 小结 区间重叠问题 0 问题分析 有一个录取学生人数表 in_school_stu,记录的是每年录取学生的人数及录取学生的学制,计算每年在校学生人数。 1 数据准备 create table in_school_stu as ( select stack(5,1,2001,2,1200,2,2000…

Vue 中 watch 和 watchEffect 的区别

watch 和 watcheffect 都是 vue 中用于监视响应式数据的 api&#xff0c;它们的区别在于&#xff1a;watch 用于监视特定响应式属性并执行回调函数。watcheffect 用于更通用的响应式数据监视&#xff0c;但回调函数中不能更新响应式数据。Vue 中 watch 和 watchEffect 的区别 …

linux下的Socket网络编程教程

套接字概念 Socket本身有“插座”的意思&#xff0c;在Linux环境下&#xff0c;用于表示进程间网络通信的特殊文件类型。本质为内核借助缓冲区形成的伪文件。与管道类似的&#xff0c;Linux系统将其封装成文件的目的是为了统一接口&#xff0c;使得读写套接字和读写文件的操作…