细说-goroutine-和-channel

50次阅读

共计 2060 个字符,预计需要花费 6 分钟才能阅读完成。

  • goroutine 看一个需要

    • 需要:要求统计 1 – 90000000000 的数字中,那些是素数?
  • 剖析思路:

    • 传统的办法,就是应用一个循环,循环的判断各个数是不是素数「效率很低」
    • 应用并发或者并行的形式,将统计素数的任务分配个多个 goroutine 去实现,这时就会应用到 goroutine「速度进步很多」
    • goroutine 根本介绍

    过程和线程介绍

    • 过程就是程序程序在操作系统中的一次执行过程,是零碎进行资源分配和调度的根本单元
    • 线程是过程的一个执行实例,是程序执行的最小单元,它是比过程更小的能独立运行的根本单元
    • 一个过程能够创立和销毁多个线程,同一个过程中的多个线程能够并发执行
    • 一个程序至多有一个过程,一个过程至多有一个线程
    • 并发和并行

      • 多线程程序在单核上运行,就是并发
      • 多线程程序在多核上运行,就是并行
    • 小结

      • 并发:因为是在一个 cpu 上,比方有 10 个线程,每个线程执行 10ms(进行轮询操作),从人的角度看,如同这 10 个线程都在运行,然而从宏观上看,

在某个工夫点看,其实只有一个线程在执行,这就是并发。

    • 并行:因为是在多个 cpu 上 (比方有 10 个 cpu),比方有 10 个线程,每个线程执行 10ms(各自在不同的 cpu 上执行),从人的角度看,这 10 个线程都在运行,然而从宏观上看,在某个工夫点看,也同时有 10 个线程在执行,这就是并行
    • go 协程和 go 主线程

      • go 主线程 (有程序员间接称为线程 / 也能够了解程过程) : 一个 go 线程上,能够起多个协程,你能够这里了解,协程是轻量级的线程「编译器做优化」
    • go 协程的特点

      • 有独立的栈空间
      • 共享程序堆空间
      • 调度由用户管制
      • 协程是轻量级的线程
    • channel (管道)- 看个需要

      • 需要:当初要计算 1 -200 的各个数的阶乘,并且把各个数的阶乘放入到 map 中,最初显示进去,要求应用 goroutine 实现

    剖析思路

    • 应用 goroutine 来实现,效率高,然而会呈现并发 / 并行平安问题
    • 这里就提出了不同的 goroutine 如何通信的问题

    代码实现

    • 应用 goroutine 来实现 (看看应用 goroutine 并发实现会呈现什么问题? 而后咱们去解决)
    • 在运行某个程序时,如何晓得是否存在资源竞争问题,办法很简略,在编译程序时。减少一个参数。-race 即可
    • 代码实现见 goroutine 和 channel/goroutine_channel.go

      下面的案例就呈现了资源的竞争的问题

    • 不同 goroutine 之间如何通信

      • 全局变量的互斥锁
      • 应用管道 channel 来解决
    • 应用全局变量加锁同步改良程序

      • 因为没有对全局变量 m 加锁,因而会呈现资源抢夺问题,代码会呈现谬误,提醒 fatal error: concurrent map writes
      • 解决方案: 退出互斥锁
      • 咱们的数的阶乘很大,后果会越界,能够将求阶乘改成 sum+=uint64(i)
      • 改良代码实现见 goroutine 和 channel/goroutine_channel_new.go
    • 为什么须要 channel

      • 后面应用全局变量加锁同步来解决 goroutine 的通信,但不完满
      • 主线程在期待所有 goroutine 全副实现的工夫很难确定,咱们这里设置 10s, 仅仅是估算
      • 如果主线程休眠工夫长了,会加长等待时间,如果工夫短了,可能还有 goroutine 处于工作状态,这时也会随主线程的退出而销毁
      • 同步全局变量加锁同步来通信,也不利用多个协程对全局变量的读写操作
      • 下面种种剖析都在召唤一个新的通信机制 - channel
    • channel 的根本介绍

      • channel 实质就是一个数据结构 - 队列
      • 数据是先进先出(FIFO:first in first out)
      • 线程平安,多 goroutine 拜访时,不须要加锁,就是说 channel 自身就是线程平安的
      • channel 有类型的,一个 string 的 channel 只能寄存 string 类型数据
      • channel 是线程平安的,多个协程操作同一个管道时,不会产生资源竞争问题
    • 定义 / 申明 channel

      • var 变量名 chan 数据类型
      • 举例:

        var intChan chan int (intChan 用户寄存 int 数据)
        var mapChan chan map[int]string (mapChan 用户寄存 map[int]string 类型 )
        var perChan chan Person
        var PerChan2 chan *Person
        ....

        阐明

        • channel 是援用类型
        • channel 必须初始化能力写入数据,即 make 后能力应用
        • 管道是有类型的,intChan 只能写入整型 int
    • 管道的初始化,写入数据到管道,从管道读取数据以及根本注意事项
      • 代码实现见 goroutine 和 channel/channel.go
    • channel 应用的注意事项

      • channel 中只能寄存指定的数据类型
      • channel 的数据放满后,就不能再放入了
      • 如果从 channel 取出数据后,能够持续放入
      • 在没有应用协程的状况下,如果 channel 数据取完了,在取,就会报 dead lock
    • 读写 channel 案例演示

      • 案例见 goroutine 和 channel/intChan.go

    ….. 具体见上面连贯

    细说 goroutine 和 channel

    正文完
     0