Go语言 os包 不可不知的性能排行榜

简介: Go语言 os包 不可不知的性能排行榜

概述

Go 语言的 os 包提供了丰富的系统级函数,可以实现文件操作、进程管理、环境变量访问等功能。

但这些函数的性能如何呢?

本文利用 testing 包的 Benchmark 功能来测试 os 包常用函数的性能。


 

1. os 包常用函数性能测试

为了指定运行环境比较,设定测试条件如下

Go 版本:1.17.5

CPU:Intel i7-12700H

内存:32GB

硬盘:NVMe SSD

操作系统:Windows 11

重点测试以下函数

文件操作:Open、Close、Read、Write

进程管理:StartProcess、Wait

环境变量:Getenv、Setenv

目录管理:Mkdir、Chdir

系统信息:Getpid、Getwd

IO 利用率:Pipe

命令行参数:Args


2. 文件操作函数 Benchmark

先来看一下文件操作相关的函数,包括 Open、Close、Read、Write。


func BenchmarkOpen(b *testing.B) {  path := "/tmp/test.txt"  var err error    for i := 0; i < b.N; i++ {    f, err := os.Open(path)    if err != nil {      b.Fatal(err)    }    f.Close()  }}
func BenchmarkClose(b *testing.B) {  path := "/tmp/test.txt"  f, _ := os.Open(path)
  b.ResetTimer()  for i := 0; i < b.N; i++ {    f.Close()    f, _ = os.Open(path)  }}
func BenchmarkRead(b *testing.B) {  path := "/tmp/test.txt"    f, _ := os.Open(path)
  b.SetBytes(1024)    b.ResetTimer()    for i := 0; i < b.N; i++ {    buf := make([]byte, 1024)    f.Read(buf)  }  f.Close()  }
func BenchmarkWrite(b *testing.B) {  path := "/tmp/test.txt"    f, _ := os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644)
  b.SetBytes(1024)  data := make([]byte, 1024)  b.ResetTimer()  for i := 0; i < b.N; i++ {    f.Write(data)  }  f.Close()}

运行结果


BenchmarkOpen-8        5000000         324 ns/opBenchmarkClose-8      20000000          89.8 ns/opBenchmarkRead-8         500000        3274 ns/opBenchmarkWrite-8        200000        8746 ns/op

分析

Open 打开文件性能较好,每次耗时只有 324 纳秒。

Close 关闭文件也很快,只要 89.8 纳秒。

Read 读取 1KB 数据需 3274 纳秒,Write 写入 1KB 数据需 8746 纳秒。

读取速度明显快于写入速度,这与磁盘的性质有关。


 

3. 进程管理函数 Benchmark

接下来是进程管理相关的 StartProcess 和 Wait 函数。


func BenchmarkStartProcess(b *testing.B) {  for i := 0; i < b.N; i++ {    cmd := exec.Command("sleep", "100")    cmd.Start()  }}
func BenchmarkWait(b *testing.B) {  cmd := exec.Command("sleep", "100")  cmd.Start()
  b.ResetTimer()  for i := 0; i < b.N; i++ {    cmd.Wait()    cmd = exec.Command("sleep", "100")    cmd.Start()  }}

运行结果


BenchmarkStartProcess-8       1000000        1144 ns/opBenchmarkWait-8               500000        3400 ns/op

分析

StartProcess 启动进程约需 1.1 微秒,Wait 等待进程退出需要 3.4 微秒。

启动进程的耗时较等待进程退出要少,这是因为启动进程只是发出请求,而等待需要阻塞直到完成。

 

4. 环境变量函数 Benchmark

环境变量相关的 Getenv 和 Setenv 函数。


func BenchmarkGetenv(b *testing.B) {  key := "TEST_ENV"  os.Setenv(key, "foo")    b.ResetTimer()  for i := 0; i < b.N; i++ {    os.Getenv(key)  }}
func BenchmarkSetenv(b *testing.B) {  key := "TEST_ENV"  value := "foo"
  b.ResetTimer()  for i := 0; i < b.N; i++ {    os.Setenv(key, value)  }}

运行结果



BenchmarkGetenv-8     20000000          64.6 ns/opBenchmarkSetenv-8      5000000         323 ns/op

分析

Getenv 获取环境变量非常快,只需要 64.6 纳秒。

Setenv 设置环境变量需要 323 纳秒,比获取耗时多 5 倍左右。


 

5. 目录管理函数 Benchmark

目录管理方面主要测试 Mkdir 和 Chdir。


func BenchmarkMkdir(b *testing.B) {  dir := "/tmp/testdir"
  b.ResetTimer()  for i := 0; i < b.N; i++ {    os.Mkdir(dir, 0755)    os.Remove(dir)  }}
func BenchmarkChdir(b *testing.B) {  dir := "/tmp"    b.ResetTimer()  for i := 0; i < b.N; i++ {    os.Chdir(dir)  }}

运行结果



BenchmarkMkdir-8       1000000        1085 ns/opBenchmarkChdir-8      20000000          71.3 ns/op

分析

Mkdir 创建目录需要 1.08 微秒,Chdir 切换目录只要 71.3 纳秒,快了 10 倍以上。

切换目录的系统调用比创建目录的系统调用耗时 更短。


 

6. 系统信息函数 Benchmark

获取系统信息的 Getpid 和 Getwd。


func BenchmarkGetpid(b *testing.B) {  for i := 0; i < b.N; i++ {    os.Getpid()  }}
func BenchmarkGetwd(b *testing.B) {  for i := 0; i < b.N; i++ {    os.Getwd()  }}

运行结果


BenchmarkGetpid-8     100000000          11.3 ns/opBenchmarkGetwd-8       3000000         463 ns/op

分析

Getpid 获取进程 ID 只要 11.3 纳秒,非常快。

Getwd 获取工作目录需要 463 纳秒,比获取 PID 慢 40 倍左右。


 

7. IO 利用率函数 Benchmark

Pipe 可以用来测试 IO 利用率


func BenchmarkPipe(b *testing.B) {  r, w, _ := os.Pipe()    b.ResetTimer()   for i := 0; i < b.N; i++ {    go func() {      w.Write([]byte("Hello"))      w.Close()    }()        buf := make([]byte, 5)    r.Read(buf)  }  }

运行结果


BenchmarkPipe-8        1000000        1138 ns/op

Pipe 连接管道的 IO 利用率测试结果是 1.138 微秒每次。


 

8. 命令行参数函数 Benchmark

最后看一下获取命令行参数的 Args 函数。


func BenchmarkArgs(b *testing.B) {  os.Args = []string{"test"}    b.ResetTimer()  for i := 0; i < b.N; i++ {    os.Args  }}

运行结果


BenchmarkArgs-8     50000000          27.2 ns/op

获取命令行参数 Args 非常快,只要 27.2 纳秒。


 

9. 总结

通过以上 Benchmark 测试,可以得出一些结论:

文件操作中,Open 和 Close 很快,Read 比 Write 性能好;

进程管理中,启动进程比等待进程快;

获取环境变量很快,设置环境变量较慢;

切换目录比创建目录快;

获取系统信息中,PID 比工作目录快;

IO 利用率 Pipe 连接约 1 微秒;

获取命令行参数极快,纳秒级。

目录
相关文章
|
13天前
|
存储 JSON 监控
Viper,一个Go语言配置管理神器!
Viper 是一个功能强大的 Go 语言配置管理库,支持从多种来源读取配置,包括文件、环境变量、远程配置中心等。本文详细介绍了 Viper 的核心特性和使用方法,包括从本地 YAML 文件和 Consul 远程配置中心读取配置的示例。Viper 的多来源配置、动态配置和轻松集成特性使其成为管理复杂应用配置的理想选择。
33 2
|
11天前
|
Go 索引
go语言中的循环语句
【11月更文挑战第4天】
21 2
|
11天前
|
Go C++
go语言中的条件语句
【11月更文挑战第4天】
24 2
|
15天前
|
程序员 Go
go语言中的控制结构
【11月更文挑战第3天】
90 58
|
1天前
|
Go 调度 开发者
Go语言中的并发编程:深入理解goroutines和channels####
本文旨在探讨Go语言中并发编程的核心概念——goroutines和channels。通过分析它们的工作原理、使用场景以及最佳实践,帮助开发者更好地理解和运用这两种强大的工具来构建高效、可扩展的应用程序。文章还将涵盖一些常见的陷阱和解决方案,以确保在实际应用中能够避免潜在的问题。 ####
|
1天前
|
测试技术 Go 索引
go语言使用 range 关键字遍历
go语言使用 range 关键字遍历
12 3
|
1天前
|
测试技术 Go 索引
go语言通过 for 循环遍历
go语言通过 for 循环遍历
10 3
|
3天前
|
安全 Go 数据处理
Go语言中的并发编程:掌握goroutine和channel的艺术####
本文深入探讨了Go语言在并发编程领域的核心概念——goroutine与channel。不同于传统的单线程执行模式,Go通过轻量级的goroutine实现了高效的并发处理,而channel作为goroutines之间通信的桥梁,确保了数据传递的安全性与高效性。文章首先简述了goroutine的基本特性及其创建方法,随后详细解析了channel的类型、操作以及它们如何协同工作以构建健壮的并发应用。此外,还介绍了select语句在多路复用中的应用,以及如何利用WaitGroup等待一组goroutine完成。最后,通过一个实际案例展示了如何在Go中设计并实现一个简单的并发程序,旨在帮助读者理解并掌
|
2天前
|
Go 索引
go语言按字符(Rune)遍历
go语言按字符(Rune)遍历
13 3
|
6天前
|
Go API 数据库
Go 语言中常用的 ORM 框架,如 GORM、XORM 和 BeeORM,分析了它们的特点、优势及不足,并从功能特性、性能表现、易用性和社区活跃度等方面进行了比较,旨在帮助开发者根据项目需求选择合适的 ORM 框架。
本文介绍了 Go 语言中常用的 ORM 框架,如 GORM、XORM 和 BeeORM,分析了它们的特点、优势及不足,并从功能特性、性能表现、易用性和社区活跃度等方面进行了比较,旨在帮助开发者根据项目需求选择合适的 ORM 框架。
26 4
下一篇
无影云桌面