Golang Tutorials-02并发

chan & select

  • chan 是并发安全的通信对象,读写使用示例:

    // 使用make 创建一个存储int 类型的chan:
    ch1 := make(chan int)

    // 向chan写入:
    ch1 <- 1

    // 从chan读出:
    i := <-ch1

    // 或者通过ok判断ch里是否有数据
    i, ok := <-ch1

    // 不接受返回值的读:
    fmt.Println(<-ch)
  • 带缓冲区的 chan: ch := make(chan int, 100)

    • 不带缓冲区的 channel, 如果 ch 已经有数据, 再向 ch 写数据会导致写入方阻塞, 如果 ch 空, 读取方会阻塞
    • 带缓冲区的 channel, 如果 ch 没满, 写入方不会阻塞
  • channel 的关闭: close(channel),:

    • 只能由 sender 关闭;
    • 调用 close 后,如果 sender 继续写入数据,会 panic;
    • 调用 close 后,receiver 接收完最后一个元素,chan 为关闭状态,尝试从 chan 读取动作不会阻塞,而是立刻返回 success;
  • 使用 select 监视一组 chan, 并从已经准备好的 chan 里随机选出一个, 用法类似 switch, 每个 case 后面是读取 chan 的操作:

    select {
    case i := <-ch1:
    fmt.Println(i)
    case j := <-ch2:
    fmt.Println(j)
    default:
    fmt.Println("?")
    }

chan 的内部实现,@ref: golang 系列:channel 全面解析 - 知乎


type hchan struct {
qcount uint // channel 里的元素计数
dataqsiz uint // 最大可以缓冲的数量

buf unsafe.Pointer // 该 buf 指向一个循环队列的数据结构

closed uint32 // 关闭状态

sendx uint // 当 channel 设置了缓冲数量时,数据区域即循环队列此时已发送数据的索引位置
recvx uint // 当 channel 设置了缓冲数量时,数据区域即循环队列此时已接收数据的索引位置

recvq waitq // 想读取数据但又被阻塞住的 goroutine 队列
sendq waitq // 想发送数据但又被阻塞住的 goroutine 队列

lock mutex

}

chan 使用范例:@ref : 深入golang之—goroutine并发控制与通信 - 知乎

CSP模型:Communicating Sequential Process,Go的Channel 和 Actor都算一种实现,二者的区别..

代码demo功能:主进程和协程通信,主进程等待协程退出

  • 共享变量实现:考虑这种做法的缺点是?
  • Channel + WaitGroup实现
  • Context + WaitGroup实现

sync

Go 语言在 sync 包中提供了用于同步的一些基本原语,包括常见的 sync.Mutex、sync.RWMutex、sync.WaitGroup、sync.Once 和 sync.Cond

@todo

os/exec

@ref:: go os/exec 简明教程

cmd基本函数:

  • cmd.Start() 和 cmd.Wait(), 其他函数的实现可以看做是对Start和Wait的封装
  • cmd.Run() = Start() + Wait()
  • cmd.CombinedOutput() = cmd. Stdout和cmd.Stderr关联同一个Buffer + Run()
    cmd属性:
    • 标准输出/错误: cmd. Stdout 和 cmd. Stderr属性
cmd := exec.Command("ls", "-lah")
var stdout, stderr bytes.Buffer
cmd.Stdout = &stdout // stdout关联Buffer
cmd.Stderr = &stderr

err := cmd.Start() // 非阻塞
if err != nil {
log.Fatalf("failed to call cmd.Start(): %v", err)
}

log.Printf("pid: %d", cmd.Process.Pid)
cmd.Process.Wait() // 阻塞直到退出
log.Printf("exitcode: %d", cmd.ProcessState.ExitCode())