• 协程使用通道来通信


    通道:用来发送类型化数据的管道(负责协程之间的通信)
    FIFO通道。

    声明:
    var identifier chan datatype
    为初始化的通道的值是nil
    所有的类型都可以用于通道、空接口。
    通道时引用类型。所以也使用make()函数类给它分配内存。

    var ch1 chan string
    ch1 = make(chan string)
    ch1 := make (chan string)

    通信操作符:
    <-
    流向通道
    ch <- int1
    流出
    num := <- ch
    <- ch

    死锁:
    1.runtime会检查main协程,如果main协程中使用的那个通道(无缓冲)没有另一端,则会报死锁
    2.有缓冲:写入几个数据,但是因为没有另一段,通道满时无法继续写入,则死锁。
    2.main协程等待一个协程给它发送数据,同时协程等待main协程给它发送数据,造成死锁。
    2.不能避免除main协程之外的协程之间的死锁,需要自己检查。

    通道阻塞:
    没办法向通道中读取或写入数据的情况就是阻塞。
    写入的情况: 无缓冲:接收者没准备好的情况
    有缓冲:通道满的时候
    读取的情况: 无缓冲:发送者没准备好的情况
    有缓冲:通道为空
    使用带缓冲的通道:
    buf := 100
    ch1 := make(chan string,buf)
    使用有缓冲的通道:更具有伸缩性。

    信号量模式:
    协程向另一个协程写入数据,表示执行结束(另一个协程等待此协程的数据)
    func A(A_B,B_A chan int){
    for {
    <- B_A
    fmt.Println("A")
    A_B<-1
    }

    }
    func B(A_B,B_A chan int){
    for {
    <-A_B
    fmt.Println("B")
    B_A<-1
    }

    }

    匿名函数(协程)内使用通道
    go func() {
    chA_B<-1
    }()
    带缓冲通道实现资源型信号量
    1.通道容量和资源数总数相同
    2.通道内元素长度与当前被使用的资源数相同
    3.通道容量减去通道元素长度等于未使用的元素总数
    P、V操作
    P操作向通道内写入多个元素以表示有多少资源被占用
    V操作向通道内写入多个元素以表示有多少元素被释放
    lock锁(建议为lock锁设置一个单独的通道(缓冲为1))
    lock,向通道内写满元素,通道被占满,其它协程使用lock就会阻塞。
    unlock,释放通道里所有的元素,使得其它协程可以继续它们的lock操作。
    通道元素的读写是原子操作。


    func P(n int){
    e := new(empty.Empty)
    for i:= 0;i<n ;i++ {
    ch1<-*e
    }
    }
    func V(n int){
    for i:= 0 ;i <n ;i++ {
    <-ch1
    }
    }
    func wait(n int){
    P(n)
    }
    func Siganl(n int){
    V(n)
    }

    chLock := make(chan int,1)
    func P(){ chLock<-1}
    func V(){ <- chLcok}
    func lock(){
    P(1)
    }
    func unlock(){
    V(1)
    }

    通道使用for循环
    for v := range ch{
    ...............
    }
    普通for(迭代)
    for i:= 0 ; i <c.len() ; i++{
    ch <- c.items[i]
    }

    通道的方向:(常用于协程的形参,使得通道可以根据固定的方向来传输)
    因为会出现在协程的函数里,一个通道既可以写也可以读,但是在大部分情况下(锁就是个特例)
    我们的通道是两个协程之间的定向传输通道。
    var send_only chan<- int (只发送)
    var recv_only <- chan int (只接收,只接收的通道无法关闭,因为关闭功能对它来说没用)

    通道被关闭:(还可以接收值)
    close(ch) 实际上是将通道标记为无法通过<- 接收值。
    (向已经关闭的通道写入数据和第二次关闭通道都会导致panic)
    测试通道是否被关闭
    v , ok := <- ch (读的第二个返回值是是否正常读取,读取原本就有的元素返回true,但是在通道关闭后,就是读取完所有元素也可以继续读取,之后也不会发生panic,会读取到一个零值和false)
    (出现false可以表示为通道被关闭了。)

    实现非阻塞通道(都不能关闭)的读取,使用select
    select {
    case u:= <- ch1:
    ...
    case v:= <- ch2:
    ...
    ...
    default: // no value ready to be received
    ...
    }
    1> 如果都阻塞了(没有default),会等待
    2> 如果多个可以处理,随机选一个
    3> 都不能处理,执行default
    func main() {
    ch1 := make(chan int)
    ch2 := make(chan int)
    ch3 := make(chan int)
    go func() {
    for {
    time.Sleep(1000)
    ch1<- 1
    ch2<- 2
    ch3<- 3
    }

    }()
    for {
    time.Sleep(100)
    select {
    case num := <-ch1:
    fmt.Println(num)
    case num := <- ch2:
    fmt.Println(num)
    case num := <- ch3:
    fmt.Println(num)
    default:
    fmt.Println("no nimber")
    }
    }

    通道、超时、计时器
    time包:
    time.Ticker结构体,以指定的时间间隔重复向通道C(内部字段)发送时间值。
    协程和恢复(recover)
    协程内发生panicking和其它协程无关。所有的处理也仅仅是在这个协程上

    使用锁(sunc.lock)的情景:
    1>访问共享数据结构中的缓存信息
    2>保存引用程序上下文和状态信息数据
    使用通道的情景:
    1>与异步操作的结果进行交互
    2>分发任务
    3>传递数据所有权

  • 相关阅读:
    V2热帖:要多健壮的代码才能支撑起千变万化的需求?
    jmeter生成html报告的命令
    jmeter5.x&4.x搭配使用Serveragent 监听服务端性能参数
    springboot关于tomcat的几个默认配置
    nginx日志统计分析-shell
    OpenStack虚拟机VIP配置步骤
    openstack 3.14.3 虚拟机增加指定IP网卡
    OpenStack各组件的常用命令
    Filebeat的Registry文件解读
    一个shell脚本的实践
  • 原文地址:https://www.cnblogs.com/mcmx/p/11390899.html
Copyright © 2020-2023  润新知