Go 语言一些常用语法编写和优化指南

Go 语言以其简洁的语法和强大的并发性能而受到开发者的喜爱。然而,为了充分利用 Go 的潜力,我们需要了解如何优化 Go 程序。本文将介绍一些常见的 Go 语言优化技巧,并通过实际例子进行说明。

## 1. 利用 `sync.Pool` 减少内存分配

在 Go 中,频繁的内存分配和释放可能会导致性能问题。`sync.Pool` 可以用于存储和复用临时对象,从而减少内存分配和垃圾回收的开销。

```
var bufPool = sync.Pool{
    New: func() interface{} {
        return make([]byte, 1024)
    },
}

buf := bufPool.Get().([]byte)
// 使用 buf...
bufPool.Put(buf)
```

在这个例子中,我们创建了一个 `sync.Pool` 来存储字节切片。当我们需要一个字节切片时,我们首先尝试从池中获取,如果池中没有可用的对象,那么 `New` 函数就会被调用来创建一个新的字节切片。使用完字节切片后,我们将其放回池中,以便后续的复用。

## 2. 使用缓冲通道进行异步操作

Go 的通道(channel)是一种在 goroutine 之间进行通信的机制。缓冲通道可以用于异步操作,从而提高程序的并发性能。

```
ch := make(chan int, 100) // 创建一个缓冲大小为100的通道

go func() {
    for i := 0; i < 100; i++ {
        ch <- i // 向通道发送数据
    }
    close(ch)
}()

for i := range ch { // 从通道接收数据
    fmt.Println(i)
}
```

在这个例子中,我们创建了一个缓冲大小为 100 的通道。然后我们启动了一个 goroutine 来向通道发送数据,主 goroutine 从通道接收数据。由于通道是缓冲的,所以发送者和接收者可以并行工作,从而提高了程序的并发性能。

## 3. 利用 `pprof` 进行性能分析

Go 标准库中的 `net/http/pprof` 包提供了一种方便的方式来分析 Go 程序的性能。我们可以通过添加一些简单的代码来启动一个 HTTP 服务器,然后通过 `pprof` 工具来获取和分析性能数据。

```
import _ "net/http/pprof"

go func() {
    log.Println(http.ListenAndServe("localhost:6060", nil))
}()
```

在这个例子中,我们启动了一个运行在 `localhost:6060` 的 HTTP 服务器。然后我们可以通过 `go tool pprof http://localhost:6060/debug/pprof/profile` 命令来获取 CPU profile,或者通过 `go tool pprof http://localhost:6060/debug/pprof/heap` 命令来获取内存 profile。

## 4. 使用 `strings.Builder` 进行字符串拼接

在 Go 中,字符串是不可变的,这意味着每次字符串拼接操作都会创建一个新的字符串。如果你需要进行大量的字符串拼接操作,这可能会导致大量的内存分配和垃圾回收。`strings.Builder` 是 Go 语言中用于高效字符串拼接的工具。

```
var builder strings.Builder

for i := 0; i < 1000; i++ {
    builder.WriteString("Hello, World!")
}

result := builder.String()
```

在这个例子中,我们使用 `strings.Builder` 来进行 1000 次字符串拼接操作。与直接使用 `+` 或 `+=` 进行字符串拼接相比,`strings.Builder` 可以显著提高性能。

## 5. 利用 `time.After` 避免 goroutine 泄露

在 Go 中,如果一个 goroutine 在完成任务后没有被正确地关闭,那么它可能会一直占用内存,这被称为 goroutine 泄露。`time.After` 是一种常用的防止 goroutine 泄露的技巧。

```
func doSomethingWithTimeout(timeout time.Duration) {
    done := make(chan bool)
    go func() {
        // 做一些耗时的操作...
        done <- true
    }()

    select {
    case <-done:
        // 操作成功完成
    case <-time.After(timeout):
        // 操作超时
    }
}
```

在这个例子中,我们启动了一个 goroutine 来执行一些耗时的操作,然后使用 `select` 语句等待操作的完成或超时。如果操作在超时时间内完成,那么 `done` 通道会接收到一个值,`select` 语句会退出。如果操作在超时时间内没有完成,那么 `time.After` 会发送一个值,`select` 语句会退出,goroutine 会被正确地关闭。

## 6. 使用 `strconv` 而不是 `fmt` 进行字符串转换

在 Go 中,`fmt.Sprintf` 是一种常用的将其他类型的值转换为字符串的方法。然而,`fmt.Sprintf` 的性能通常不如 `strconv` 包中的函数。

```
s := fmt.Sprintf("%d", 123) // 不推荐

s := strconv.Itoa(123) // 推荐
```

在这个例子中,我们比较了 `fmt.Sprintf` 和 `strconv.Itoa` 两种将整数转换为字符串的方法。虽然 `fmt.Sprintf` 更灵活,但 `strconv.Itoa` 的性能更好。

## 7. 使用索引访问切片元素

在 Go 中,使用 `range` 循环遍历切片是一种常见的做法。然而,如果你只需要访问切片的元素,而不需要元素的索引,那么使用索引访问元素通常会有更好的性能。

```
for i := range slice {
    _ = slice[i] // 推荐
}

for _, v := range slice {
    _ = v // 不推荐
}
```

在这个例子中,我们比较了使用 `range` 循环和使用索引访问切片元素的两种方法。虽然使用 `range` 循环更简洁,但使用索引访问元素的性能更好。

## 8. 避免在循环中创建 goroutine

在 Go 中,`go` 关键字可以用于创建新的 goroutine。然而,如果你在循环中创建 goroutine,那么可能会导致大量的 goroutine 被创建,从而消耗大量的内存。

```
for _, v := range slice {
    go func(v int) {
        // 处理 v...
    }(v)
}
```

在这个例子中,我们在循环中为每个元素创建了一个新的 goroutine。虽然这样可以并行处理元素,但如果切片的大小很大,那么可能会创建大量的 goroutine,从而消耗大量的内存。因此,我们应该避免在循环中创建 goroutine,或者使用一些技术(如使用 `sync.WaitGroup` 或者使用通道)来限制 goroutine 的数量。
# Go 语言优化指南(续)

在前几篇文章中,我们已经介绍了一些常见的 Go 语言优化技巧。在这篇文章中,我们将继续探讨更多的优化技巧,并通过实际例子进行说明。

## 9. 使用 `sync.Map` 进行并发安全的映射操作

在 Go 中,内置的 `map` 类型不是并发安全的,这意味着你不能在多个 goroutine 中同时对同一个 `map` 进行读写操作。`sync.Map` 是 Go 语言中用于并发安全的映射操作的工具。

```
var m sync.Map

m.Store("hello", "world") // 存储键值对

value, ok := m.Load("hello") // 加载键值对
if ok {
    fmt.Println(value)
}
```

在这个例子中,我们使用 `sync.Map` 来存储和加载键值对。与内置的 `map` 相比,`sync.Map` 的性能可能稍微差一些,但它可以在多个 goroutine 中安全地使用。

## 10. 利用 `context` 包进行超时和取消操作

在 Go 中,`context` 包提供了一种在 API 边界之间传递超时、取消信号以及其他请求范围的值的机制。

```
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()

select {
case <-time.After(2 * time.Second):
    fmt.Println("overslept")
case <-ctx.Done():
    fmt.Println(ctx.Err())
}
```

在这个例子中,我们创建了一个会在一秒后自动取消的 `context`。然后我们等待两秒或 `context` 被取消。由于 `context` 会在一秒后被取消,所以 `ctx.Err()` 会返回一个错误,表明 `context` 已经被取消。

## 11. 使用 `atomic` 包进行并发安全的操作

在 Go 中,`sync/atomic` 包提供了一些原子操作函数,可以用于实现并发安全的计数器、标志等。

```
var counter int64

go func() {
    for {
        atomic.AddInt64(&counter, 1)
        time.Sleep(time.Millisecond)
    }
}()

go func() {
    for {
        fmt.Println(atomic.LoadInt64(&counter))
        time.Sleep(time.Second)
    }
}()
```

在这个例子中,我们创建了一个并发安全的计数器。一个 goroutine 每毫秒将计数器加一,另一个 goroutine 每秒打印计数器的当前值。由于我们使用了 `atomic` 包中的函数,所以这个计数器在多个 goroutine 中是安全的。

## 12. 利用 `reflect` 包进行动态操作

在 Go 中,`reflect` 包提供了一种在运行时动态操作对象的机制,包括获取对象的类型和值、调用方法等。

```
v := reflect.ValueOf(123)
t := reflect.TypeOf(123)

fmt.Println(v.Int()) // 输出:123
fmt.Println(t.Name()) // 输出:int
```

在这个例子中,我们使用 `reflect` 包获取了一个整数的值和类型。虽然 `reflect` 包非常强大,但它的性能通常不如静态类型的操作,所以我们应该谨慎使用。

## 13. 使用 `sort` 包进行高效排序

Go 语言的 `sort` 包提供了一系列函数用于对切片和自定义数据结构进行排序。

```
nums := []int{3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5}
sort.Ints(nums)
fmt.Println(nums) // 输出:[1 1 2 3 3 4 5 5 5 6 9]
```

在这个例子中,我们使用 `sort.Ints` 函数对一个整数切片进行排序。`sort` 包还提供了其他函数,如 `sort.Float64s`、`sort.Strings` 等,用于对特定类型的切片进行排序。

## 14. 利用 `encoding/json` 包进行 JSON 操作

Go 语言的 `encoding/json` 包提供了一系列函数用于处理 JSON 数据。

```
type Person struct {
    Name string `json:"name"`
    Age  int    `json:"age"`
}

jsonStr := `{"name":"John","age":30}`
var p Person
json.Unmarshal([]byte(jsonStr), &p)
fmt.Println(p) // 输出:{John 30}
```

在这个例子中,我们定义了一个 `Person` 结构体,并使用 `json.Unmarshal` 函数将一个 JSON 字符串解析到这个结构体中。`encoding/json` 包还提供了其他函数,如 `json.Marshal` 等,用于将 Go 数据结构转换为 JSON 字符串。

## 推荐系列
来来来,老铁们,男人女人都需要的技术活 拿去不谢:远程调试,发布网站到公网演示,远程访问内网服务,
 https://juejin.cn/post/7285929996841271311

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

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

相关文章

Windows 自带的 Linux 子系统(WSL)安装与使用

WSL官网安装教程&#xff1a; https://learn.microsoft.com/zh-cn/windows/wsl/install Windows 自带的Linux子系统&#xff0c;比用VM什么的香太多了。可以自己看官方教程&#xff0c;也可以以下步骤完成。 如果中间遇到我没遇到的问题百度&#xff0c;可以在评论区评论&#…

Redis(03)——发布订阅

基础命令 基于频道 publish channel message&#xff1a;将信号发送到指定的频道pubsub subcommand [argument [argyment]]&#xff1a;查看订阅或发布系统状态subscribe channel [channel]&#xff1a;订阅一个或多个频道的信息unsubscribe [channel [channel]]&#xff1a;退…

Java——Stream流的学习

在开发过程中&#xff0c;经常或忽略流的使用&#xff0c;导致用的不熟练&#xff0c;于是抽时间系统的学习下stream的使用&#xff0c;找了哔哩哔哩的教程跟着看看练练。 准备工作 创建Book、Aurhor实体类&#xff0c;初始化数据 public static List<Author> getAuth…

【Go语言最佳实践:永远不要启动一个停止不了的 goroutine】

前面的例子显示当一个任务时没有必要时使用 goroutine。但使用 Go 语言的原因之一是该语言提供的并发功能。实际上&#xff0c;很多情况下你希望利用硬件中可用的并行性。为此&#xff0c;你必须使用 goroutines。 这个简单的应用程序在两个不同的端口上提供 http 服务&#x…

解锁文档处理新境界:ONLYOFFICE编辑功能为开发者带来新机遇

引言 ONLYOFFICE最新发布的文档8.0版本带来了一系列引人注目的功能和优化&#xff0c;为用户提供了更强大、更高效的在线编辑体验。这次更新涵盖了多个方面&#xff0c;包括PDF表单、RTL支持、单变量求解、图表向导以及插件界面设计更新等。这些新功能不仅提升了文档处理的便利…

day 22

时间获取: 1.time time_t time(time_t *tloc); 功能: 返回1970-1-1到现在的秒数&#xff08;格林威治时间&#xff09; 参数: tloc:存放秒数空间首地址 返回值: 成功返回秒数 失败返回-1 2.localtime struct …

职业资格高级执法考试试题及答案,分享几个实用搜题和学习工具 #知识分享#微信

作为当代大学生&#xff0c;我们常常面临着繁重的学业压力和众多的学习任务。在这个信息爆炸的时代&#xff0c;如何高效地进行搜题和学习成了我们迫切需要解决的问题。幸运的是&#xff0c;随着科技的不断进步&#xff0c;我们拥有了许多方便、实用的日常搜题和学习软件。 1.…

旗舰配置,巅峰性能 | 一文玩转铁威马 『F4-424 Pro』强大的Docker虚拟机功能【附产品开箱】

旗舰配置&#xff0c;巅峰性能 | 一文玩转铁威马 『F4-424 Pro』强大的Docker&虚拟机功能【附产品开箱】 哈喽小伙伴们&#xff0c;我是Stark-C~ 开篇 记得还在两个月之前&#xff0c;我为大家介绍了国产“开箱即用”的国民专业级NAS『铁威马』&#xff1a; &#x1f53…

idea代码review工具Code Review Helper使用介绍

之前在团队里面遇到一个关于代码review的问题&#xff0c;使用gitlab自己的还是facebook的Phabricator&#xff0c;很难看到整体逻辑&#xff0c;因为业务逻辑代码可能不在这次改动范围内&#xff0c;在去源库中找不好找。针对这个刚需&#xff0c;在网上找了一个idea的代码工具…

kali安装awvs报错error creating the database

修改host文件 vim /etc/hosts 加入 127.0.0.1 kali 重启再安装即可解决

软件实例分享,操作简单美发店会员登记记账本vip会员管理系统软件教程

软件实例分享&#xff0c;操作简单美发店会员登记记账本vip会员管理系统软件教程 一、前言 以下软件程序教程以 佳易王美发店会员管理系统软件V16为例说明 软件文件下载可以点击最下方官网卡片——软件下载——试用版软件下载 1、新会员可以直接使用手.机号&#xff0c;不需…

WordPress有没有必要选择付费主题

有必要。 能用付费的&#xff0c;就尽量别用免费的。 付费主题&#xff0c;情况也比较复杂&#xff0c;先讲一下付费主题的几种情况 1、是原创付费主题。是主题制作者原创的主题。 2、是把别人的主题二次开发的付费主题。这个有些是有原始开发者授权的&#xff0c;有些就是…

解libvirt中Domain类的方法

libvirt是一个用于管理虚拟化平台的开源工具包&#xff0c;提供了对不同虚拟化技术&#xff08;如KVM、QEMU、Xen等&#xff09;的统一管理接口。在libvirt中&#xff0c;Domain类表示虚拟机&#xff08;domain&#xff09;对象&#xff0c;并提供了丰富的方法来管理虚拟机的各…

Kernelized Correlation Filters KCF算法原理详解(阅读笔记)(待补充)

KCF 目录 KCF预备知识1. 岭回归2. 循环移位和循环矩阵3. 傅里叶对角化4. 方向梯度直方图&#xff08;HOG&#xff09; 正文1. 线性回归1.1. 岭回归1.2. 基于循环矩阵获取正负样本1.3. 基于傅里叶对角化的求解 2. 使用非线性回归对模型进行训练2.1. 应用kernel-trick的非线性模型…

如何使用IP代理解决亚马逊账号IP关联问题?

亚马逊账号IP关联问题是指当同一个IP地址下有多个亚马逊账号进行活动时&#xff0c;亚马逊会将它们关联在一起&#xff0c;从而可能导致账号被封禁或限制。 为了避免这种情况&#xff0c;许多人选择使用IP代理。 IP代理为什么可以解决亚马逊IP关联问题&#xff1f; IP代理是…

【LLVM】nsw和nuw的一个例子

nsw和nuw是LLVMIR提供给二元运算的flag。分别表示not signed wrap和not unsigned wrap。在LLVM2.6的更新日志中表述如下&#xff1a; The add, sub and mul instructions now support optional “nsw” and “nuw” bits which indicate that the operation is guaranteed to n…

欲速则不达,慢就是快!

引言 随着生活水平的提高&#xff0c;不少人的目标从原先的解决温饱转变为追求内心充实&#xff0c;但由于现在的时间过得越来越快以及其他外部因素&#xff0c;我们对很多东西的获取越来越没耐心&#xff0c;例如书店经常会看到《7天精通Java》、《3天掌握XXX》等等之类的书籍…

金山下的wps,无法删除水印

RT&#xff0c;正常删除水印的流程是&#xff0c;插入-水印-删除水印。 如图的操作方法不生效时&#xff0c;可用下面的方法 点击页眉或页脚&#xff0c;进入页眉的编辑模式&#xff0c;可以看到水印变成可以选中的状态&#xff0c;选中&#xff0c;点击delete或者鼠标右键删…

数衍科技连接CRM和营销系统,无代码API集成

{无代码开发的优势} 在数字化转型的浪潮中&#xff0c;无代码开发为企业带来了巨大的便利。数衍科技&#xff0c;这家专注于生态数据服务的国家高新技术企业&#xff0c;提供了一种无需依赖传统API开发的解决方案。企业可以通过其无代码开发平台&#xff0c;迅速构建数据连接&…

[AIGC] 垃圾回收算法

垃圾回收算法 垃圾回收是一种自动化的内存管理方法。其核心目标是找出程序中不再使用的动态分配的内存块&#xff0c;并将其标记为可重用&#xff0c;以便能够进行新的内存分配。 下面我们将介绍三种主要的垃圾回收算法&#xff1a;标记清除算法、复制算法和标记压缩算法。 …