go学习记录——第八天
标准库
类似于fmt
和os
的库在Golang
中有150+个,被称为标准库(和python的什么math啊,os一样)(附录中D有详细的书里引用的包的列表,书的地址见 go学习记录——第三天
unsafe
包含一个打破 Golang “类型安全”的命令,一般不会使用(估计这辈子用到的概率比彗星撞地球还低)syscall
-os
-os/exec
os
提供一个与平台无关的操作系统功能接口,采用类Unix的设计,旨在隐藏不同操作系统之间的差异,使得文件系统和操作系统对象保持一致(os
属于对syscall
进行了封装,整体会更加快速,简化复杂性,不必顾虑底层细节)。同时在错误处理方面采用了Go风格的错误处理机制,能够在函数返回时提供更多的错误信息而不是简单的错误码os/exec
提供我们运行外部操作系统命令和程序的方式(就比如我们可以使用该包连接到PowerShell
,然后执行go env
命令)示例代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22package main
import (
"fmt"
"log"
"os/exec"
)
func main() {
// 创建命令对象,指定要执行的PowerShell命令
cmd := exec.Command("powershell.exe", "-Command", "go env")
// 获取命令的输出
output, err := cmd.Output()
if err != nil {
log.Fatal(err)
}
// 打印输出结果
fmt.Println(string(output))
}syscall
底层的外部包,提供了操作系统底层调用的基本接口
示例代码
1 |
|
这里需要说明的是原本的syscall.Syscall
已经被弃用了,所以我改了一下,使用golang.org/x/sys/unix
去完成类似的操作,代码如下
1 |
|
archive/tar
和compress/gzip
压缩(解压缩)文件功能fmt
-io
-bufio
-path/filepath
-flag
fmt
提供格式化输入输出功能(类似于C中的printf
和scanf
,用法是fmt.Println
fmt.Printf
fmt.Scan
fmt.Scanf
)io
提供基本输入输出功能,主要围绕系统功能的封装(输入输出接口用法Reader
Writer
主要是让不同的输入输出流能够通过统一的接口进行操作,常用函数有io.Copy
io.ReadAll
,主要是是哦不同的输入输出流之间复制数据或读取数据)bufio
缓冲输入输出功能的封装(缓冲功能就是通过在读取和写入时使用缓冲区,减少对系统调用的次数,提高性能,常用的有bufio.Reader
bufio.Writer
)path/filepath
用来操作系统中目标文件名路径(提供了处理文件路径的函数,比如文件的扩展名、合并路径、获取绝对路径等,同时还支持跨平台的处理,比如对Windows和Linux之间的路径分隔符的差异进行处理)flag
对命令行参数的相关操作(说白了就是对命令行参数的解析,能够允许开发者去定义和解析命令行参数,使得程序能够接收用户传入的参数,常用函数有flag.String
flag.Int
等函数去定义不同类型的参数)
string
-strconv
-unicode
-regexp
-bytes
string
提供了对字符串进行操作的函数(比如对字符串查找、替换、分割、连接,判断字符串的前后缀,大小写转换等)strconv
对字符串和基本数据类型进行转化(和python的数据类型转化类似,把字符串转为其他类型,其他类型转字符串)unicode
提供对 Unicode 字符的处理功能(判断字符是否属于某个类型(字母啊数字啊这些),提供对字符的特定操作)regexp
提供正则化表达式的支持,用于字符串的模式匹配和操作(查找、替换、验证字符串是否符合某个格式,支持复杂的正则表达式语法)bytes
提供了对字节切片的操作(有点类似于string
但更注重于字节数据,提供对字节数据的高效处理)
math
-math/cmath
-math/rand
-sort
-math/big
math
提供基本数学函数和常数,支持浮点数的各种数学运算(比如三角函数呀(Sin Cos Tan)幂函数呀(Pow Sqrt Log)特殊函数呀(Inf NaN Hypot)都有)math/cmath
提供处理复数的数学运算,有类似于math
的函数,但是运用于复数类型的(有一说一除了高考那一道复数题我都八百年没听过这玩意了,好久远的存在)math/rand
提供伪随机数生成器(和python著名的rand.random类似!我恨随机数,秋招鬼知道多少公司采用随机抽取简历)sort
提供对切片和自定义集合的排序功能(这玩意我可太熟悉了,python是不是就得来个sort)math/big
对大数进行运算(比如big.Int
整数运算big.Float
高精度浮点数运算big.Rat
有理数运算)
container/list
-ring
-heap
container/list
主要是实现双向链表的数据结构(每个节点分别包含一个指向前和指向后的指针,常用方法有PushBack(value)
尾部添加元素PushFront(value)
头部添加元素Remove(element)
删除指定元素Init()
初始化链表)container/ring
主要是实现环形链表的数据结构(最后一个节点指向第一个节点,适合循环访问元素的场景,常用方法有Next()
返回下一个元素Prev()
返回前一个元素Value
获取或设置当前节点的值)container/heap
主要是实现堆数据结构(用于实现优先队列,Golang的堆是基于sort.Interfacce
实现的,允许用户定义自己的数据类型并实现相应的接口,常用方法Init(h)
初始化堆Push(h, x)
向堆中加入元素Pop(h)
从堆中移除并返回最小(或最大)元素)
time
-log
time
提供了对时间和日期的基本操作,包含了获取当前时间、时间格式化、时间计算等(time.Now()
获取当前时间time.Format()
时间格式化为字符串time.Parse()
字符串解析为时间)log
提供了简单的日志记录功能,允许开发者在程序允许时记录信息、错误和调试信息(log.Print()
log.Println()
log.Printf()
记录信息log.Fantal()
log.Panic()
记录错误并终止log.SetPrifix()
log.SetFlags()
自定义日志输出格式
encoding/json/xml
-text/template
encoding/json
用于处理JSON
数据的编码和解码(json.Marshal(v interface{})
将数据结构编码为JSON格式json.Unmarshal(data []byte, v interface{})
将JSON
数据解码到指定的Go
的数据结构中encoding/xml
提供了对xml
数据的编码和解码功能(xml/Marshal(v interface{})
将数据结构编码为XML格式xml.Unmarshal(date []byte, v interface{})
将XML数据编码到指定的Go
数据结构中
net
-net/http
-html
net
用于网络编程呢的核心组件,提供了对网络I/O的基本操作,包括TCP、UDP、域名解析等(通过Dial
和Listen
函数创建TCP或UDP链接,用net.LookupHost
net.ResolveIPAddr
等函数进行域名解析)net/http
提供了HTTP客户端和服务器的实现,支持处理HTTP请求和响应(http.ListenAndServer
启动HTTP服务处理客户端请求hettp.Get
http.Post
等方法发起HTTP请求http.Request
http.ResponseWriter
处理请求和响应)
runtime
- 垃圾回收(GC)负责自动管理内存,回收不用的对象(这里我的理解是和python的类似,问了下AI给了个表)
Go Python 策略 三色标记-清除算法(分为黑白灰三类,白潜在,灰被检查,黑确定清除) 引用计数 回收机制 并发回收(垃圾回收与程序执行并发进行) 标记-清除和分代回收 相似之处 旨在自动管理内存,减少内存泄露风险 都是用标记-清除来识别不再使用的对象 不同之处 并发操作 为即时处理,可能会导致出现程序暂停 - 协程创建与管理,使用关键词
go
即可创建新的协程并进行调度控制等操作
reflect
实现通过程序允许时反射,让程序操作任意类型的变量
regexp包
简单模式的话可以直接使用Match()
方法
1 |
|
变量ok
将返回true
or false
,也可以使用MatchString()
1 |
|
下面将使用Compile()
方法返回一个Regexp
对象,并且涉及到匹配、查找、替换
示例代码:
1 |
|
输出结果
1 |
|
除了Compile()
我们还可以使用MustComplie()
,这个方法会去检查我们正则的有效性,如果不合法时将panic()
。换句话说,Compile()
是可能返回错误的
锁和sync包
看到锁就想到了SQL里在面试的时候最怕也是最烦的锁相关问题,呕,但是继续学吧。
当我们遇到未知变量对我们已经固定好的线程顺序进行了修改(也就是资源抢夺,多个线程对同一变量使用进行抢夺),接下来就要说怎么去解决。
最经典的做法就是一次只允许一个线程对共享变量进行操作。当变量被一个线程改变时,我们就需要上锁(这不就是排他锁吗),直到我们该线程完成执行后解锁,其他线程才能进行访问。
在前面接触的map
中就不存在锁机制,由于其需要考虑性能,所以并没有该类设计。所以map
类型数据在并行被访问时就有可能出错。
一般来说的解决方案就是两种,sync.Mutex
和 sync.RWMutex
,但是在Go 1.9中引入了sync.map
,一个专为并发设计的map
。
sync.Mutex
这个其实就是我们所说的排他锁(互斥锁),作用就是在临界区对同一时间能够进入的线程数进行控制(只允许一个)。
现在,假设info
是一个需要上锁的在共享内存中的变量
1 |
|
然后如果想改变变量可以写
1 |
|
还有一个例子是通过Mutex
来实现一个可以上锁的共享缓冲器
1 |
|
这个结构体的整体就是有一个排他锁去保证buffer
能够在任何时刻只被一个goroutine
访问,而缓冲器则是提供了动态增长的字节切片,适合高效的字节拼读和读取。
再回到我们的sync
来,在这里面还有一个RWMutex
锁,也是前面提到过的,主要作用就是在同一时间允许多线程访问但只允许单线程进行写操作。还有Lock()
和一般的Mutex
的作用是一样的。包里还有一个Once
类型变量的方法once.Do(call)
这个方法是确保被调用函数只能被调用一次(莫名想到了之前写的一个python的东西)
综上所述,一般情况下snyc
包可以解决同一时间只能一个线程访问变量或map
类型数据的问题,但是涉及到程序运行速度变慢或其他问题,我们又需要去思考其他解决办法,书里给的是通过goroutines
or channels
去解决,不过这部分得在后面才有,咱就先写一下,后面再说。
今天就先到这里吧,package的东西还有点多,明儿再学