Docker 基本使用

启动一个容器 打个样 1 docker run -itd --rm --name hello image_name – it 将当前的终端和容器内的终端连接在一起, 正式所谓的交互模式 –rm 当容器停止之后, 会自动删除改容器 外挂文件夹 参数 -v docker run -it -v /home/dock/Downloads:/usr/Downloads ubuntu64 /bin/bash 与容器交互 进入容器 docker attach exec docker -it exec CONTAIN_NAME bash exex 会再目标容器内部执行一个命令, 命令名为 bash, 就是起一个 shell 咯. 加上 -it, 进入交互的终端模式 查看日志 docker logs CONTAINER 可以查看容器日志 -f 可以持续输出容器内部的最新日志 管理容器 启动 1 docker start CONTAINER 暂停 1 docker stop CONTAINER 提交 1 docker commit --author="ian" CONTAINER NEW-IMAGENAME:TAG 管理镜像 查看所有的镜像列表 ...

<span title='2022-04-07 13:34:55 +0800 +0800'>April 7, 2022</span>&nbsp;·&nbsp;1 min&nbsp;·&nbsp;潜水员

Channel

Go 中 channel 中用法和实现总结 以下分析和源码都是基于 go1.17 版本 channel 简介 Go 语言的基础类型之一, 用于在协程与协程之间传递数据 (channel 数据的传输方式也是值传递, Go语言的数据传输只有值传递) Do not communicate by sharing memory; instead, share memory by communicating. channel 保证: 数据的先入先出 并发情况下的数据安全 已经关闭的 channel 不可重开 channel 的实现 channel 在内部实现的结构体为 runtime.hchan 有一个环形链表, 暂存要传输的数据. 无 buffer 的channel 该队列长度为0, 所以不进行数据缓冲. 有一把互斥锁mutex, 在并发情况下, 保护自身数据结构的一致性 有两个协程等待链表, 用于挂载因为发送/接收而阻塞在该 channel 上的协程 1 2 3 4 5 6 7 8 9 10 11 12 13 14 type hchan struct { qcount uint // 当前 buffer 中有暂存着多少个数据 dataqsiz uint // 环形数组的buffer个数, 由 make 初始化的时候第二个参数容量决定的 buf unsafe.Pointer // 环形数组开始地址 elemsize uint16 // channel 传输的元素大小, 用于计算内存大小 closed uint32 // channel 是否已经关闭 0未关闭, 非0关闭 elemtype *_type // element type # channel 元素的类型 sendx uint // 环形链表中, 发送数据存储的下标 recvx uint // 环形链表中, 接受数据获取数据的下标 recvq waitq // 阻塞在该 channel 等待获取数据的 Groutine 列表 sendq waitq // 阻塞在该 channel 等待写入数据的 Groutine 列表 lock mutex // # 互斥锁 用于保护自身数据变更 } 初始化 channel 传递的元素不能太大 如果是空结构体或者无缓冲队列, 是不需要分配环形队列内存 如果传递数据类型有内含指针, 需要将环形队列分配到堆上 内部实现函数runtime.makechan ...

<span title='2022-04-02 10:09:22 +0800 +0800'>April 2, 2022</span>&nbsp;·&nbsp;11 min&nbsp;·&nbsp;潜水员

Go 常用的命令汇总

工具分类 go build 编译源代码文件 -race 编译出的目标程序,会启用数据竞争检测 go doc 查看包的文档(定义于doc.go的注释中), 于包中公开的函数签名 example 1 2 3 go doc go doc encoding/json go env 查看 go 相关的环境变量 1 2 3 4 5 # -w 设置环境变量 go env -w GOPAHT='/some/path' # -u 恢复成默认设置 go env -u GOPATH go generate 扫描文件中的指令并执行, 相关指令目的应该是“生成或者修改源文件” 注释的指令格式 //go:generate command argument... ps: wire 也是利用命令, 生成依赖注入文件 go get 管理当前module依赖 1 2 3 4 5 6 7 8 # 添加依赖包 go get example.com/pkg # 指定包版本 go get example.com/pkg@1.2.3 # 移除依赖 go get example.com/pkg@none go install 获取包文件,并编译和安装。可执行文件编译到$GOBIN路径下, 包文件编译到$GOPATH/pkg ...

<span title='2022-04-01 19:56:59 +0800 +0800'>April 1, 2022</span>&nbsp;·&nbsp;1 min&nbsp;·&nbsp;潜水员

Hugo 文章分类管理

Hugo 文章分类管理 文件夹 内容存放在content/目录下方, content/下方的子目录会形成资源URI, 例如 content/blog/doc.md 文章访问目录即为 https//XXX.github.io/blog.doc.md 分类管理 文章内容表述 (Front Matter) 使用进行分类, 默认只有tags 1 2 3 tags: - Go - fast 可以在config添加自定的分类选项 1 2 3 taxonomies: series: series category: categories 文章路径 类别 描述 地址 home 网站homepage /index.html page 指定页面 /post/页面/index.html section 分区 /section/index.html taxonomy 分类 /tags/index.html term 分类系列 /tags/go/index.html _index.md 和 index.md 在文件夹下方添加_index.md会识别成section. 在文件夹下方添加index.md会被识别成文章. 千万不要在默认的content目录下方添加index.md

<span title='2022-03-09 11:29:17 +0800 +0800'>March 9, 2022</span>&nbsp;·&nbsp;1 min&nbsp;·&nbsp;潜水员

0 min&nbsp;·&nbsp;潜水员

进程, 线程, 协程 进程 进程一般由程序、数据集合和进程控制块三部分组成。 程序用于描述进程要完成的功能,是控制进程执行的指令集; 数据集合是程序在执行时所需要的数据和工作区; 程序控制块(Program Control Block,简称PCB),包含进程的描述信息和控制信息,是进程存在的唯一标志。 进程是程序的实例,一个程序可以有多个实例,但一个实例只能对应一个进程 线程 线程是程序执行中一个单一的顺序控制流程,是程序执行流的最小单元,是处理器调度和分派的基本单位。 一个进程可以有一个或多个线程,各个线程之间共享程序的内存空间(也就是所在进程的内存空间)。一个标准的线程由线程ID、当前指令指针(PC)、寄存器和堆栈组成。而进程由内存空间(代码、数据、进程空间、打开的文件)和一个或多个线程组成 任务调度 大部分操作系统(如Windows、Linux)的任务调度是采用时间片轮转的抢占式调度方式。 多线程与多核 多核(心)处理器是指在一个处理器上集成多个运算核心从而提高计算能力,也就是有多个真正并行计算的处理核心,每一个处理核心对应一个内核线程。 内核线程(Kernel Thread,KLT)就是直接由操作系统内核支持的线程,这种线程由内核来完成线程切换,内核通过操作调度器对线程进行调度,并负责将线程的任务映射到各个处理器上。一般一个处理核心对应一个内核线程,比如单核处理器对应一个内核线程,双核处理器对应两个内核线程,四核处理器对应四个内核线程。 超线程技术就是利用特殊的硬件指令,把一个物理芯片模拟成两个逻辑处理核心 程序一般不会直接去使用内核线程,而是去使用内核线程的一种高级接口——轻量级进程(Lightweight Process,LWP),轻量级进程就是我们通常意义上所讲的线程,也被叫做用户线程。由于每个轻量级进程都由一个内核线程支持,因此只有先支持内核线程,才能有轻量级进程。 线程切换 线程切换的实现一般放在内核,中断处理程序也是放在内核。从这个角度来说,如果线程当前处于用户态,若要发生线程切换,必然是要先要先进入内核态,发生状态切换的。线程切换的原因还可能是其他类型的中断,或者线程自身主动进入等待或者睡眠,这些情况无一例外都是要进入内核的。 线程的切换分两种情况: 同进程内, 和不同进程内切换; 线程模型 一对一模型: 一个用户线程对应一个内核线程 CON 许多操作系统限制了内核线程的数量,因此一对一模型会使用户线程的数量受到限制; 许多操作系统内核线程调度时,上下文切换的开销较大,导致用户线程的执行效率下降。 一对多模型: 多个用户线程对应一个内核线程 CON 如果其中一个用户线程阻塞,那么其它所有线程都将无法执行,因为此时内核线程也随之阻塞了; 在多处理器系统上,处理器数量的增加对多对一模型的线程性能不会有明显的增加 多对多模型: 多个用户线程对应一个内核线程 PRO 一个用户线程的阻塞不会导致所有线程的阻塞,因为此时还有别的内核线程被调度来执行; 多对多模型对用户线程的数量没有限制; 在多处理器的操作系统中,性能得到提升 协程 协程,英文Coroutines,是一种基于线程之上,但又比线程更加轻量级的存在,这种由程序员自己写程序来管理的轻量级线程叫做『用户空间线程』,具有对内核来说不可见的特性 因为是自主开辟的异步任务,所以很多人也更喜欢叫它们纤程(Fiber),或者绿色线程(GreenThread) 为什么使用协程 由于现代CPU发展的越来越快,每一个时间片能够处理的指令越来越多,很经常导致一个线程时间片还未用完,而进入了等待数据IO的时间。此时该线程必然要让出CPU,让另一个线程运行 之后有人提出了协程的概念,让同一个线程在一个CPU时间片内可以处理多个任务,虽然协程的切换也耗费时间,但总体来说要比线程的切换要好很多。因此,使用协程可以比使用线程能够得到更好的处理效果(这个不是一定的,还得跟服务器的任务性质以及协程的调度算法有关系,但一般情况下使用协程会比使用线程有更好的性能) 协程解决什么 协程的目的就是当出现长时间的I/O操作时,通过让出目前的协程调度,执行下一个任务的方式,来消除ContextSwitch上的开销。 避免CPU一直等待IO, 增加延迟 同时可以避免创建过多的线程, 造成更多上下文切换 进程 vs 线程 线程与进程最大的区别在于,线程是调度的基本单位,而进程则是资源拥有的基本单位。 所谓内核中的任务调度,实际上的调度对象是线程;而进程只是给线程提供了虚拟内存、全局变量等资源。 当进程只有一个线程时,可以认为进程就等于线程。 当进程拥有多个线程时,这些线程会共享相同的虚拟内存和全局变量等资源。这些资源在上下文切换时是不需要修改的。 另外,线程也有自己的私有数据,比如栈和寄存器等,这些在上下文切换时也是需要保存的 线程的上下文切换分成两种: 前后两个线程属于不同进程。此时,因为资源不共享,所以切换过程就跟进程上下文切换是一样 前后两个线程属于同一个进程。此时,因为虚拟内存是共享的,所以在切换时,虚拟内存这些资源就保持不动,只需要切换线程的私有数据、寄存器等不共享的数据 协程 vs 线程 items thread goroutine 资源占用 8M 2k 调度所属 OS 用户 切换开销 涉及模式切换、16个寄存器 PC/SP/DX 性能 创建和销毁开销大 小 数据同步 依赖锁 只有一个线程,不存在同时写变量冲突,在协程中控制共享资源不加锁 寄存器 ...

1 min&nbsp;·&nbsp;潜水员

什么是TCP TCP —— 用于保证可靠性和流控制机制的数据,包括 Socket、序列号以及窗口大小 The combination of this information, including sockets, sequence numbers, and window sizes, is called a connection. 为什么要三次握手 如果通信双方的通信次数只有两次,那么发送方一旦发出建立连接的请求之后它就没有办法 撤回这一次请求,如果在网络状况复杂或者较差的网络中,发送方连续发送多次建立连接的 请求,如果 TCP 建立连接只能通信两次,那么接收方只能选择接受或者拒绝发送方发起的请 求,它并不清楚这一次请求是不是由于网络拥堵而早早过期的连接。 所以,TCP 选择使用三次握手来建立连接并在连接引入了 RST 这一控制消息,接收方当收到 请求时会将发送方发来的 SEQ+1 发送给对方,这时由发送方来判断当前连接是否是历史连接: 如果当前连接是历史连接,即 SEQ 过期或者超时,那么发送方就会直接发送 RST 控制消息中止这一次连接; 如果当前连接不是历史连接,那么发送方就会发送 ACK 控制消息,通信双方就会成功建立连接; 使用三次握手和 RST 控制消息将是否建立连接的最终控制权交给了发送方,因为只有发送方 有足够的上下文来判断当前连接是否是错误的或者过期的,这也是 TCP 使用三次握手建立连 接的最主要原因。 初始序列号 获得一个用于发送信息的初始化序列号 TCP 连接的发起方可以通过保存发出的序列号判断连接是否过期,如果让接收方来保存并 判断序列号却是不现实的,这也再一次强化了我们在上一节中提出的观点 —— 避免历史错 连接的初始化。

1 min&nbsp;·&nbsp;潜水员