前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【GO入门到放弃】Golang标准库-syscall

【GO入门到放弃】Golang标准库-syscall

作者头像
五分钟学SRE
发布2023-12-05 18:11:34
1.7K0
发布2023-12-05 18:11:34
举报
文章被收录于专栏:五分钟学SRE

syscall 是 Go 语言标准库中提供的一个用于调用底层操作系统 API 的包。它支持多种操作系统,包括 Linux、Windows、Darwin 等。我们可以使用 syscall 包来实现一些底层的系统功能,如进程管理、信号处理、文件操作等。

在开始介绍go sys call 库之前先介绍下Linux syscall的几个概念

Linux syscall(系统调用)

Linux syscall(系统调用)是一种Linux内核提供的编程接口,允许应用程序直接请求操作系统核心的服务,例如读写文件、网络通信、进程管理等。。在Linux中,系统调用是应用程序与操作系统之间进行交互的主要方法之一,也是编写底层系统软件、优化性能和增强安全性的重要手段。

用户态与内核态

在Linux操作系统中,内核是操作系统的核心部分,用于管理计算机硬件、进程调度、内存管理等。为了保证内核运行的稳定性和安全性,Linux采用了一种特殊的运行模式:用户态和内核态。

用户态是指应用程序运行的环境,应用程序只能访问自己的内存空间和系统资源,不能直接访问操作系统内核,必须通过系统调用来请求内核执行操作。在用户态中,CPU访问内存的地址是虚拟地址,操作系统会将虚拟地址映射到物理地址上。

内核态是指操作系统内核运行的环境,具有更高的权限和更广泛的访问权限。在内核态中,CPU访问内存的地址是物理地址,操作系统可以直接访问硬件资源。操作系统内核运行时处于内核态。

系统调用类型

在Go语言中,syscall库支持的系统调用类型与Linux syscall(是一种Linux内核提供的编程接口,允许应用程序直接请求操作系统核心的服务)类似,该包中的每个函数都直接映射到相应的Linux系统调用。由于Go语言具有跨平台的优势,因此syscall包在各种平台上都可以使用。主要包括以下几类:

  1. 进程控制:创建、终止、等待进程、设置进程优先级等。
  2. 文件操作:打开、读取、写入文件等。
  3. 网络操作:建立、连接、断开网络连接等。
  4. 内存管理:申请、释放内存等。
  5. 时间管理:获取、设置系统时间等。
  6. 设备操作:读写设备、设置设备参数等。

我们写一些demo 来实际体验下这个包的应用

使用 syscall 包实现了以下功能:

代码语言:javascript
复制
syscall.Getpid():获取当前进程的进程 ID。
syscall.Getuid():获取当前进程的用户 ID。
syscall.Getgid():获取当前进程的组 ID。
syscall.Getpagesize():获取系统的页大小。
syscall.Open():打开一个文件。
syscall.Close():关闭一个文件。
syscall.Read():读取一个文件的内容。
代码语言:javascript
复制
syscall_demo.go
代码语言:javascript
复制
代码语言:javascript
复制
package main

import (
    "fmt"
    "syscall"
)

func main() {
    // 获取进程 ID
    pid := syscall.Getpid()
    fmt.Println("Process ID:", pid)

    // 获取进程用户 ID
    uid := syscall.Getuid()
    fmt.Println("User ID:", uid)

    // 获取进程组 ID
    gid := syscall.Getgid()
    fmt.Println("Group ID:", gid)

    // 获取系统页大小
    pagesize := syscall.Getpagesize()
    fmt.Println("Page size:", pagesize)

    // 打开一个文件
    fd, err := syscall.Open("/etc/hosts", syscall.O_RDONLY, 0)
    if err != nil {
        fmt.Println("Failed to open file:", err)
        return
    }
    defer syscall.Close(fd)

    // 读取文件内容
    //声明并初始化一个 byte 类型的切片(slice),其长度为 1024 个字节。这个切片用于存储从文件中读取的内容。
    buf := make([]byte, 1024)
    //使用 syscall 包中的 Read 函数从文件中读取数据,并将结果存储在 buf 变量中。Read 函数接受两个参数:文件描述符(fd)和一个 byte 类型的切片(buf),它返回读取的字节数(n)和一个可能出现的错误(err)。这里的 fd 是之前打开文件得到的文件描述符。
    n, err := syscall.Read(fd, buf)
    if err != nil {
        fmt.Println("Failed to read file:", err)
        return
    }
    fmt.Printf("Read %d bytes from file:\n%s\n", n, buf[:n])
}
代码语言:javascript
复制

执行结果

代码语言:javascript
复制
代码语言:javascript
复制
go run syscall_demo.go
pid :  135442
uid :  0
gid :  0
pagesize :  4096
read 39 bytes from file :
test
test1
let us use syscall
bingo!!!
代码语言:javascript
复制

在使用 syscall 包时,我们需要注意一些与底层操作系统相关的细节。例如,文件描述符(fd)在 Unix 系统中是一种重要的概念,我们需要使用 syscall.Open() 函数打开一个文件,并返回一个文件描述符。使用完文件描述符后,我们需要使用 syscall.Close() 函数将其关闭。在读取文件时,我们需要使用 syscall.Read() 函数,而不是标准库中的 io.Read() 函数。

同时,由于不同操作系统支持的功能不同,我们在使用 syscall 包时需要根据实际情况进行调用。例如,Windows 系统中可能不支持某些功能,或者实现方式与 Unix 系统中不同。

使用syscall 对系统调用的优化

使用syscall.Mmap()提高文件I/O性能

与Linux syscall类似,使用syscall.Mmap()可以将文件映射到进程的虚拟内存中,减少I/O操作次数,提高I/O性能

demo code

代码语言:javascript
复制
代码语言:javascript
复制
package main

import (
"fmt"
"os"
"syscall"
)

func main() {
// 打开文件
file, err := os.OpenFile("syscall_mmap.txt", os.O_RDWR, 0666)
if err != nil {
    panic(err)
}
defer file.Close()

// 将文件映射到进程的虚拟内存中
//使用 syscall.Mmap() 函数将文件 "yscall_mmap.txt" 的前 1024 字节映射到进程的虚拟内存中,并设置映射的权限为 PROT_READ|PROT_WRITE,映射的方式为 MAP_SHARED,表示映射后的文件内容可以被多个进程共享。
data, err := syscall.Mmap(int(file.Fd()), 0, 1024, syscall.PROT_READ|syscall.PROT_WRITE, syscall.MAP_SHARED)
if err != nil {
    panic(err)
}
//在函数结束前调用 syscall.Munmap() 函数释放映射后的内存。
defer syscall.Munmap(data)

// 修改映射后的文件内容
//修改映射后的文件内容,将 "hi go syscall mmap" 的字节序列复制到映射后的内存中。因为映射后的内存已经和文件关联,所以修改内存的内容也会修改文件的内容
copy(data, []byte("hi go syscall mmap"))
fmt.Println(string(data))
}
代码语言:javascript
复制

运行

代码语言:javascript
复制
代码语言:javascript
复制
echo "hi  go syscall mmap" >syscall_mmap.txt
echo "Learn SRE in five minutes , become an expert" >>syscall_mmap.txt
go run syscal_mmap.go
代码语言:javascript
复制

打印

代码语言:javascript
复制
代码语言:javascript
复制
hi go syscall mmapp
Learn SRE in five minutes , become an expert
代码语言:javascript
复制

常见的gin框架就使用到了syscall.Mmap()进行优化,Gin 框架使用了 x/net/trace 包来对 HTTP 请求进行跟踪,而在跟踪时需要将请求和响应的信息写入文件,因此 Gin 框架使用 syscall.Mmap() 将日志文件映射到进程的虚拟内存中,以提高日志文件的写入性能。

使用 syscall.Poll() 提高网络 I/O 性能

syscall.Poll() 函数可以用来等待文件描述符上的事件。在进行网络 I/O 时,我们可以使用 syscall.Poll() 函数来等待网络事件,从而避免了频繁的系统调用,提高了网络 I/O 的性能。

gnet 是一个基于 Reactor 模式的高性能网络库,它使用 syscall.Poll() 函数来等待网络事件,并使用 Goroutine 来处理网络事件。这种方式可以显著提高网络 I/O 的性能。

使用 syscall.Syscall() 调用系统调用

syscall.Syscall() 函数可以用来直接调用操作系统提供的系统调用。在进行一些底层操作时,我们可以使用 syscall.Syscall() 函数来直接调用系统调用,从而避免了一些高层的封装,提高了程序的性能。

containerd 是一个面向容器的运行时环境,它需要进行一些底层的操作,例如创建进程、挂载文件系统等。在进行这些操作时,containerd 使用 syscall.Syscall() 函数直接调用系统调用,从而避免了一些高层的封装,提高了程序的性能。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2023-02-21,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 五分钟学SRE 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Linux syscall(系统调用)
  • 用户态与内核态
  • 使用syscall.Mmap()提高文件I/O性能
  • 使用 syscall.Poll() 提高网络 I/O 性能
  • 使用 syscall.Syscall() 调用系统调用
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档