GO语言核心30讲 实战与应用 (io包,bufio包,os包,网络服务,http,性能分析)

 原站地址:Go语言核心36讲_Golang_Go语言-极客时间

一、io包中的接口和工具

1. strings.Builder、strings.Reader 和 bytes.Buffer 这些类型实现了 io 包的很多接口,目的是什么

    是为了提高不同程序实体之间的互操作性。 程序实体是指比如网络和文件。

    比如 io.Copy:  func Copy(dst Writer, src Reader) (written int64, err error)

    里面的 Writer 和 Reader 可以是网络,也可以是文件,只要实现了io.Reader接口和io.Writer接口就都可以了。可以把不同的实体抽象成一个统一的实体。

2. 扩展接口和实现类型的区别是什么?

   实现类型是一个结构体; 扩展接口只是通过结构体的方式,嵌入了其他数据类型,达到扩展原有数据类型功能的目的,

   扩展接口是多个接口的集合。要实现扩展接口,需要实现多个接口。

   实现类型是把接口实现了,而扩展接口并没有把接口实现,它只是多个接口的集合。

3. 在io包中,io.Reader的扩展接口实现类型都有哪些? (提升对io包的了解程度)

    io.Reader的扩展接口有下面几种:

(1) io.ReadWriter:包含字节序列读取方法Read,和写入方法Write。

(2) io.ReadCloser:包含字节序列读取方法Read,和关闭方法Close。Close用于关闭数据读写的通路。这个接口是io.Reader和io.Closer的组合。

(3) io.ReadWriteCloser:io.Reader、io.Write 和io.Closer的组合。

(4) io.ReadSeeker:可以根据给定的偏移量去寻找新的位置,作为下一次读的起始索引。包含了寻找读写位置的基本方法Seek。io.Reader 和io.Seeker的组合。

(5) io.ReadWriteSeeker:io.Reader、io.Writer和io.Seeker的组合。

   io.Reader接口的实现类型有下面几种:

(1) *io.LimitedReader:方法Read返回的总数据量会受到限制,无论被调用多少次。

(2) *io.SectionReader:Read方法只能够读取原始数据中的某一个部分。与切片类似,只暴露在窗口之中的数据。

(3) *io.teeReader:接受io.Reader和io.Writer两个类型的参数,把Reader读到的数据,通过字节切片中转的方式,写入io.Writer处。通常使用在数据流的处理中,比如计算下载速度。

(4) *io.multiReader:接受多个io.Reader类型的参数,并从中顺序地读取数据。

(5) *io.pipe:同步内存管道的核心实现

(6) * io.PipeReader:同步内存管道的读取端

4. io包中的接口都有哪些?

(1) 核心接口:io.Reader、io.Writer和io.Closer

(2) io.ByteReader:读取一个单一的字节。 strings.Reader和bytes.Buffer 是它的实现类型。

     io.RuneReader:读取一个单一的Unicode 字符。strings.Reader和bytes.Buffer 是其实现类型

     io.ByteScanner:读取和读回退单个字节

     io.RuneScanner:读取和读回退单个Unicode 字符

     io.ReaderAt:只读取数据,不修改已读计数的值。

     io.ReaderFrom:从一个 Reader 中读取数据

     io.WriteTo:将数据写入到一个 Writer 中

     io.ReadWriter:读和写, *io.pipe 是其实现类型。

     io.ReadWriteCloser:读写和关闭管道,net包有它的实现类型。

     io.ByteWriter和io.WriterAt:功能和上面对应。实现类型是 *os.File

     io.Seeker:寻找并设定下一次读取或写入时的起始索引位置。strings.Reader和io.SectionReader都是其实现类型。

    io.Closer:关闭管道。io.PipeReader和io.PipeWriter 是其实现类型。

(3) io包中的简单接口共有 11 个。读取操作相关的5 个,写入操作相关的 4 个,关闭操作有关的1 个,读写位置设定相关的一个。此外,还包含了 9 个基于这些简单接口的扩展接口。

二、bufio包中的数据类型

1. bufio 包的程序实体,是在包装简单 I/O 接口类型值的基础上,添加了缓冲区

2. bufio包中的数据类型主要有:(1) Reader (2) Scanner (3) Writer 和 ReadWriter。

3. bufio.Reader类型值中的缓冲区起着怎样的作用?

        Reader值会预先从底层读取器里读出一部分数据,暂存于缓冲区之中。当Reader值下次读取数据时,先从缓冲区中读取。 减少了底层读取器的使用次数,降低读取的执行时间。 

        虽然,读取时会增加填充缓冲区的操作,但从总体上看,平均执行时间会有大幅度的缩短。

4. bufio.Reader类型通过私有的 fill方法 来整理缓冲区,把已读的空间腾出来,提供给底层读取器存放数据。

    整理方法就是把 [已读计数, 已写计数) 范围内的数据往最前面搬运,如下图所示:

5. bufio.Reader类型读取方法分别有哪些?

(1) Peek方法:读取缓冲区中的n个未读字节,n大于缓冲区长度的话,转而直接从底层读取器中读出数据。

      会从已读计数代表的索引位置开始读,读完不更改已读计数。 

(2) Read方法:其他和Peek方法一样,但会更改已读计数。 

(3) ReadSlice方法:持续地读取数据,直至遇到调用方给定的分隔符为止。

     如果缓冲区满了仍然找不到分隔符,会把整个缓冲区作为第一个结果值,缓冲区已满错误作为第二个结果值 返回。

(4) ReadBytes方法: 其他和ReadSlice方法一样,但缓冲区满了仍然找不到分隔符的话,会再次调用ReadSlice方法,整理缓冲区之后继续从底层读取器中读出数据,直至少找到分隔符或者读完全部数据。

6. 内容泄露:Peek方法、ReadSlice方法和ReadLine方法都有可能会造成内容泄露,因为他们都是返回直接基于缓冲区的字节切片。 只有Read方法不会内容泄露。

三、使用os包中的API

1. os代码包中的 API,是对操作系统的某方面功能的高层次抽象,使我们可以用统一的方式,操纵不同的操作系统。

    最有代表性的就是数据类型 os.File,它实现了io包3 个核心接口io.Reader、io.Writer和io.Closer,3 个简单接口,io.ReaderAt、io.Seeker和io.WriterAt,以及9 个扩展接口中的 7 个。

    所以除 文本文件、二进制文件、压缩文件、目录这些常见的形式之外,还有符号链接、各种物理设备、命名管道,以及套接字(socket)都可以被视为文件。

2. 怎样才能获得一个os.File类型的指针值(File值)? 

(1) os.Create函数:根据给定的路径创建一个新的文件。 

      会返回一个File值和一个错误值。可以通过File值进行读写,路径不存在的话会返回错误。

(2) os.Open函数:打开一个文件并返回包装了该文件的File值。

      只能从该File值中读取内容,而不能写入内容。

(3) os.NewFile函数:依据已经存在的文件描述符,新建包装了该文件的File值。

(4) os.OpenFile函数:新建或打开文件。

     可读可写。函数有 3 个参数,为name(文件路径)、flag(操作模式)和perm(权限模式)。

     可以视为这是基础函数,上面3个函数只是这个基础函数的参数组合。

3. 文件描述符,作为某个文件的一个标识存在。由 I/O 相关的系统调用返回,是很小的非负整数。

    任何文件的I/O 操作都需要这个文件描述符,它被存储在File值中。

4. File值的操作模式都有哪些?

    os.O_APPEND:追加模式写入内容。

    os.O_CREATE:路径不存在时创建文件。

    os.O_SYNC:在打开的文件上实施同步 I/O,保证读写的内容总会与硬盘上的数据同步。

    os.O_TRUNC:文件已存在时清空文件内容。

    多个操作模式可以通过按位或操作符 " | " 组合起来的。

5. File值的权限模式都有哪些?

    权限模式参数 是uint32类型的再定义类型,包含了 32 个比特位,每个比特位都有特定含义:

(1) 最高比特位,1 代表 目录。

(2) 第 26 个比特位,1代表 命名管道

(3) 最低的 9 个比特位才用于文件的权限,分别是 文件所有者、用户组、其他用户 对该文件的访问权限(读、写和执行)。

四、访问网络服务

1. 进程间通信,称为 IPC。主要方法包括:系统信号(signal)、管道(pipe)、套接字(socket)、文件锁、消息队列、信号量(semaphore)等。 socket 是最为通用和灵活的一种。

2. socket实例相关的API,是由一个名为 socket系统调用 代表的,它是连接应用程序和操作系统内核的桥梁。

    syscall代码包中,有一个与这个 socket系统调用 相对应的函数。函数本身是平台不相关的。在其底层,Go 为每个操作系统都做了适配,所以无论在哪个平台上总是有效的。

    net代码包中的很多程序实体,都会直接或间接地使用到syscall.Socket函数,比如net.Dial函数

3. net.Dial函数的第一个参数network有哪些可选值?

(1) TCP、TCP4、TCP6:代表 TCP 协议,自适应、第四版、第六版

(2) UDP、UDP4、UDP6:代表 UDP 协议,自适应、第四版、第六版

(3) unix、unixgram、unixpacket:代表 Unix 通信域下的内部 socket 协议,socket 类型分别为SOCK_STREAM、SOCK_DGRAM、SOCK_SEQPACKET。

4. 有消息边界,是指内核程序在发送或接收数据时,是以消息为单位的。

    有逻辑连接,是指通信双方在收发数据之前必须先建立网络连接

5. TCP 没有消息边界,有逻辑连接。 好处:保证可靠性,有序,双向传输。坏处:速度慢。

    UDP 有消息边界,没有逻辑连接。好处:速度快。坏处:不保证可靠,无需,只能单向传输。

6. net.DialTimeout函数 调用时给定的超时时间意味着什么?

   给定的超时时间,意味着函数为网络建立连接,可以等待的最长时间。

   调用net.DialTimeout函数之后,时间主要花费在 “解析参数network和address的值”,以及“创建 socket 实例并建立网络连接”这两件事情上。

五、基于HTTP协议的网络服务

1. net/http代码包 可以使用 基于http协议的网络服务。比如 http.Get函数。

    实例:  resp, err := http.Get(url)    返回两个值:resp 和 err

    resp:数据类型是*http.Response,响应内容的结构体。

    err:数据类型是error,创建、发送请求、接收和解析、响应 全过程中,可能发生的错误。

2. http.Get函数

    http.Get函数会在内部使用 缺省HTTP客户端,它是 net/http包中的公开变量DefaultClient代表的,其类型是 *http.Client, 它是开箱即用的。

3. http.Client类型中的 Transport字段 代表着什么?

(1) Transport字段 的数据类型是 *http.Transport,会在内部使用net.Dialer类型值,实现 连接 和 超时 的功能。

(2) http.Transport类型的值(以下简称Transport值)会对每一个网络服务的空闲连接的总数做出限定。 一个网络服务由网络地址、网络协议、代理 三方面来鉴定。

     在默认情况下,空闲连接总数最大为100,而每个网络服务的最大空闲连接数为2。

(3) *http.Transport 是 http.RoundTripper接口 的实现类型。RoundTripper 内部有一个DefaultTransport的缺省值。 前面提到的 缺省HTTP客户端 DefaultClient ,其实也就是使用这个DefaultTransport。

(4) 总的来说 Transport字段代表着:向网络服务发送 HTTP 请求,并从网络服务接收 HTTP 响应的整个操作过程。

4. http.Server类型的ListenAndServe方法都做了哪些事情?

(1) 对一个基于 TCP 协议的网络地址进行监听(net.Listen),并对接收到的 HTTP 请求进行处理。

(2) 默认开启针对网络连接的存活探测机制,以保证连接是持久的。

(3) 该方法会一直执行,直到有严重的错误发生或者被外界关掉。

5. net.Listen函数都做了哪些事情?

(1) 解析参数值中网络地址包含的 IP 地址端口号

(2) 根据给定的网络协议,确定监听的方法,并开始进行监听。

6. http.Server类型的Serve方法是怎样接受和处理 HTTP 请求的?

(1) listen之后,进入一个for循环。

(2) for循环中,Accept方法会被不断地调用,该方法返回两个值:

     net.Conn类型:代表包含了新到来的 HTTP 请求的网络连接

     error类型:代表是否发生了错误。暂时性的错误的话for会继续执行,否则会for循环都会被终止

(3) 把 net.Conn类型的结果值包装成一个*http.conn类型,并启用新的 goroutine ,去调用这个conn值的serve方法,来对当前的 HTTP 请求进行处理。

六、程序性能分析基础

1. 性能分析 API 在这三个代码包中:

(1) runtime/pprof

(2) net/http/pprof

(3) runtime/trace

2. 概要文件(Profile)

   runtime 代码包中包含更底层的 API,用来收集程序运行过程中的一些关键指标,并生成概要文件,提供分析使用。

    go test 命令也可以在测试完成后生成 概要文件(Profile)。

3. 概要文件采样时刻的内容

      分析程序性能的概要文件有CPU、内存、阻塞三种概要文件。文件里每段概要信息都记录着,某个采样时刻的内容分别是:

(1) CPU 概要文件:CPU 上正在执行的 Go 代码。

(2) 内存概要文件:内存的使用情况,已分配和已释放的字节数量和对象数量。

(3) 阻塞概要文件:goroutine 阻塞事件

4. 概要文件内容格式

    这些概要文件是以二进制存储的,是通过 protocol buffers 生成的二进制字节流。

    可以使用 go tool pprof 工具查看。

5. 怎样让程序对 CPU 概要信息进行采样?

(1) 进行采样调用StartCPUProfile函数;停止采样调用StopCPUProfile函数。

(2) StartCPUProfile函数,会设定 CPU 概要信息的采样频率,并在单独的 goroutine 中进行收集和输出。 CPU采样频率总是固定100赫兹的,经过大量实验证明最优。

(3) StopCPUProfile函数,会采样频率设为0,采样工作停止。

6. 怎样设定内存概要信息的采样频率?

(1) 为 runtime.MemProfileRate变量赋值即可。 含义是,每分配多少个字节,就对堆内存的使用情况进行一次采样。缺省值是512 KB。

(2) 越早设定越好,避免运行时造成不良影响。最好只在main函数的开始处设定一次。

(3) 想获取内存概要信息的时候, 调用WriteHeapProfile函数。但它并非实时数据,是在最近一次的内存垃圾收集工作完成时产生的。

(4) 可以调用runtime.ReadMemStats函数,获得实时数据。不过该函数会引起 Go 语言调度器的短暂停顿。

7. 怎样获取到阻塞概要信息?

(1) 调用runtime包中的SetBlockProfileRate函数,可对阻塞概要信息的采样频率进行设定。

(2) 函数有一个名叫rate的参数,int类型。含义是,只要发现一个阻塞事件的持续时间达到了多少纳秒,就对其进行采样。

(3) 在runtime包中,有一个名叫blockprofilerate的私有变量,uint64类型。含义是,只要发现一个阻塞事件的持续时间跨越了多少个 CPU 时钟周期,就对其进行采样。和(2)的区别仅仅在于单位不同。 

(4) 缺省值是0,所以默认情况下并不会记录任何阻塞事件。

(5) 需要获取阻塞概要信息的时候,做两步操作:

    调用runtime/pprof包中的 Lookup函数 并传入参数值"block",得到*runtime/pprof.Profile类型的值     

    调用Profile值的 WriteTo方法,把概要信息写进指定的写入器中。

8. runtime/pprof.Lookup函数的正确调用方式是什么?

(1) Lookup函数的功能是,提供 给定的名称 相对应的概要信息。

(2) 给定的名称 包括:

goroutine:收集当前正在使用的所有 goroutine 堆栈跟踪信息。会引起 Go 调度器的短暂停顿。

heap:收集与堆内存的分配和释放有关的采样信息。也就是前面的内存概要信息。

allocs:与heap大致一样,但 allocs 收集到的是已分配空间(已分配不管有否释放),heap是在用空间(已分配未释放)。

threadcreate:收集堆栈跟踪信息,描绘出代码调用链。

block:在代码同步竞争中被阻塞的代码的堆栈跟踪信息。就是前面的阻塞概要信息。

mutex:在代码同步竞争中,获得过执行的代码的堆栈跟踪信息。

9. 如何为基于 HTTP 协议的网络服务添加性能分析接口?

(1) 在程序中导入net/http/pprof代码包。

     import _ "net/http/pprof"

(2) 启动网络服务并开始监听。

     log.Println(http.ListenAndServe("localhost:8082", nil))

(3) 在浏览器中访问  http://localhost:8082/debug/pprof  看到一个简约的网页

(4) 在/debug/pprof/ 这个URL路径下还有很多可用的子路径,包括:profile,trace,allocs、block、goroutine、heap、mutex、threadcreate。

(5) 返回二进制内容时,需要使用  go tool pprof 工具去查看。

    go tool pprof http://localhost:6060/debug/pprof/profile?seconds=60

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

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

相关文章

43. 字符串相乘

题目 给定两个以字符串形式表示的非负整数 num1 和 num2,返回 num1 和 num2 的乘积,它们的乘积也表示为字符串形式。 **注意:**不能使用任何内置的 BigInteger 库或直接将输入转换为整数。 示例 1: 输入: num1 "2", num2 &qu…

python:functools.partial和functools.wraps使用

python:functools.partial和functools.wraps使用 1 前言 python内置的functools模块,提供了一些非常好用的类或者方法,其中functools.partial和functools.wraps的使用频率较高,本文将针对其分析使用。 2 使用 2.1 functools.p…

好易点 | 上海厨卫展首秀人气爆棚,智能阳台备受瞩目

2024年5月14日,第28届中国国际厨房、卫浴设施展览会(简称:上海厨卫展)在上海盛大开幕。作为厨卫行业的年度盛事,本次展会不仅汇聚了众多国内外知名品牌,更成为了展示前沿五金厨卫臻品的重要平台。其中&…

k8s 二进制安装 详细安装步骤

目录 一 实验环境 二 操作系统初始化配置(所有机器) 1,关闭防火墙 2,关闭selinux 3,关闭swap 4, 根据规划设置主机名 5, 做域名映射 6,调整内核参数 7, 时间同步 三 部署 dock…

图数据库原理在构建实体血缘关系图中的应用与实践

在当今复杂的数据驱动型应用中,理解和管理实体间的复杂关系变得日益重要。通过低代码平台进行配置的应用,因采用了DSL语言进行统一设计,要让专业开发者和非专业开发者都能快速实现复杂应用的构建,实体之间的数据逻辑和关系梳理就尤…

PyQt5 中的 List View

文章目录 1. 基础概念2. 创建 List View2.1 PyQt5 中一个简单的 List View 实例2.2 代码解释2.3 运行结果 3. 数据模型3.1 标准模型3.2 自定义模型 4. 自定义 List View4.1 使用样式表 (QSS)4.2 设置项委托 (Item Delegate) 5.事件处理6. 与数据交互6.1 添加数据6.2 删除数据6.…

【JAVA入门】Day05 - 面向对象

【JAVA入门】Day05 - 面向对象 文章目录 【JAVA入门】Day05 - 面向对象一、对象的设计和使用1.1 类和对象1.2 类的分类 二、封装三、private 关键字四、this 关键字五、构造方法六、JavaBean七、对象的内存图7.1 一个对象的内存图7.2 两个对象的内存图7.3 两个引用指向同一个对…

后仿真中的关于延时问题(如何指定延时模式)

了解到这里,大家可能会有个疑问:据我们常见,一个模块中不仅包含specify块,还会包含大量的门单元等语句。我们通常在specify块中会指定模块路径延迟, 模块内的路径单元(基本的门级单元、开关级元件或者子模块)又存在分布延迟,。 模块中这两种延迟经常会共存,那么此时进行仿真…

Cadence 16.6 PCB Edito如何将鼠标中键反向拉拽改为正向拖拽

Cadence 16.6 PCB Editor如何将鼠标中键反向拉拽改为正向拖拽 Cadence 16.6 PCB Editor默认鼠标中键是反向的拉拽,让我很不适应,在网上找的可行的方法,在这里总结出来,希望能帮到其他工程师。 按照以下步骤进行操作: …

TypeScript基础知识:TypeScript是什么?为什么会出现TypeScript?TypeScript相较于javascript有那些优势?

TypeScript(简称:TS)是JavaScript的超集(JS有的TS 都有)。 图解就是: TypeScriptType javaScript(在JS 基础之上,为JS 添加了类型支持)。 TypeScript 是微软开发的开源编程语言,可以在任何运行JavaScript的地方运行。 那么为什么要出现type…

LLMjacking:针对云托管AI大模型服务的新型攻击

Sysdig威胁研究团队(TRT)观察到一种新型攻击,命名为LLMjacking。它利用窃取的云凭证,对托管在云上的十个大型语言模型(LLM)服务发起攻击。 这些凭证是从一个流行的目标获得,即运行着一个存在漏洞的Laravel版本(CVE-2021-3129&…

Media Encoder 2024 for Mac:专业的音视频编码神器

Media Encoder 2024 for Mac,作为Mac用户的专业音视频编码工具,凭借其强大的功能和用户友好的界面,深受专业人士的喜爱。它支持将各种格式的音视频素材转换为多种流行格式,如MP4、MOV、AVI等,满足不同的播放和发布需求…