大道如青天,协程来通信,Go lang1.18入门精炼教程,由白丁入鸿儒,Go lang通道channel的使用EP14

众所周知,Go lang的作用域相对严格,数据之间的通信往往要依靠参数的传递,但如果想在多个协程任务中间做数据通信,就需要通道(channel)的参与,我们可以把数据封装成一个对象,然后把这个对象的指针传入某个通道变量中,另外一个协程从这个通道中读出变量的指针,并处理其指向的内存对象。

通道的声明与创建


package main

import "fmt"

func main() {
    var a chan int
    if a == nil {
        fmt.Println("通道是空的, 不能使用,需要先创建通道")
        a = make(chan int)
        fmt.Printf("数据类型是: %T", a)
    }
}

这里注意,通道声明之后还需要进行创建。

也可以通过海象操作符声明并创建:

package main

import "fmt"

func main() {

    a := make(chan int)

    fmt.Printf("数据类型是: %T", a)

}

程序返回:

数据类型是: chan int%

如此,一个类型为整形的通道就创建好了。

此外,通道是引用数据类型:

package main

import (
    "fmt"
)

func main() {
    ch1 := make(chan int)
    fmt.Printf("%T,%p\n", ch1, ch1)

    test1(ch1)

}

func test1(ch chan int) {
    fmt.Printf("%T,%p\n", ch, ch)
}

程序返回:

chan int,0x1400010e060
chan int,0x1400010e060

可以看到,在test1函数内和main函数内通道的地址是一样的,所以他们指向的都是同一个通道。

通道的使用

通道创建之后,即可以在协程之间充当桥梁:

package main

import "fmt"

func job(ch1 chan int) {

    ch1 <- 1 } func main() { ch1 :="make(chan" int) fmt.println(ch1) go job(ch1) data 从ch1通道中读取数据 fmt.println("data-->", data)
    fmt.Println("main&#x3002;&#x3002;over&#x3002;&#x3002;&#x3002;&#x3002;")
}
</->

这里我们声明一个函数job,把通道作为参数传递进去,注意这里参数类型除了声明通道本身以外,还得声明通道具体的数据类型。

随后在main函数中,可以理解为主协程,创建通道ch1,执行开启协程任务job,在job函数内,往通道内传递数字1

接着,主协程获取通道内由job协程传递的数据:

0x1400006a060
data--> 1
main&#x3002;&#x3002;over&#x3002;&#x3002;&#x3002;&#x3002;

藉此,就完成了数据的传递。

这里需要注意通道的调用语法:

data := <- a 读取通道 <- data 写入通道 < code></->

同步阻塞

而通道的出现,就间接帮我们实现了”阻塞”主协程的目的。

比如,多个协程任务操作一个变量:

package main

import (
    "fmt"
)

func job1(number int, squareop chan int) {
    sum := 20
    sum += number
    squareop <- sum } func job2(number int, cubeop chan int) { :="10" +="number" <- main() number ch1 ch2 go job1(number, ch1) job2(number, ch2) num1, num2 <-ch2 fmt.println("final output", num1+num2) < code></->

这里job1和job2两个协程任务同时异步执行,操作number变量,累加后往通道中写入,程序返回:

Final output 30

理论上,如果是并发执行,返回值应该是20或者10,但由于通道的存在,造成协程任务阻塞,变回了同步执行,所以返回了30。

同时,我们需要注意死锁问题,如果一个协程任务在一个通道上发送数据,那么其他的协程任务应该接收数据,如果这种情况不发生,那么程序将在运行时出现死锁。

换句话说,你发送了,就得有人接收,只发不接,或者只收不发,都会变成死锁。

此外,协程任务可以通过close(ch)方法来关闭通道:

package main

import (
    "fmt"
)

func job(ch1 chan int) {
    // &#x53D1;&#x9001;&#x65B9;&#xFF1A;3&#x6761;&#x6570;&#x636E;
    for i := 0; i < 3; i++ {
        ch1 <- i 将i写入通道中 } close(ch1) 将ch1通道关闭了。 func main() { ch1 :="make(chan" int) go job(ch1) * 子goroutine,写出数据3个 每写一个,阻塞一次,主程序读取一次,解除阻塞 主goroutine:循环读 每次读取一个,堵塞一次,子程序,写出一个,解除阻塞 发送发,关闭通道的--->&#x63A5;&#x6536;&#x65B9;&#xFF0C;&#x63A5;&#x6536;&#x5230;&#x7684;&#x6570;&#x636E;&#x662F;&#x8BE5;&#x7C7B;&#x578B;&#x7684;&#x96F6;&#x503C;&#xFF0C;&#x4EE5;&#x53CA;false
    */
    //&#x4E3B;&#x7A0B;&#x5E8F;&#x4E2D;&#x83B7;&#x53D6;&#x901A;&#x9053;&#x7684;&#x6570;&#x636E;
    for {

        v, ok := <-ch1 其他goroutine,显示的调用close方法关闭通道。 if !ok { fmt.println("已经读取了所有的数据,", ok) break } fmt.println("取出数据:", v, fmt.println("main...over....") < code></-ch1></->

这里将0到2写入chl通道,然后关闭通道。主函数里有一个死循环。类似while,它轮询通道是否在发送数据后,使用变量ok进行判断。如果ok是假的,则意味着通道关闭,因此循环结束,否则将会继续进行无限轮询。

select关键字

select 是 Go lang里面的一个流程控制结构,和switch关键字差不多,但是select会随机执行一个可运行的通道通信,如果没有通道通信可运行,它将阻塞,直到有通道通信可运行:

package main

import (
    "fmt"
    "time"
)

func job(ch1 chan int) {

    time.Sleep(2 * time.Second)
    ch1 <- 200 } func main() { ch1 :="make(chan" int) ch2 go job(ch1) job(ch2) select case num1 fmt.println("ch1中取数据。。", num1) num2, ok if fmt.println("ch2中取数据。。", num2) else fmt.println("ch2通道已经关闭。。") < code></->

这里select会随机选择一个可运行的通道通信逻辑,可能是ch1通道,也有可能是ch2通道:

&#x279C;  mydemo git:(master) &#x2717; go run "/Users/liuyue/wodfan/work/mydemo/hello.go"
ch1&#x4E2D;&#x53D6;&#x6570;&#x636E;&#x3002;&#x3002; 200
&#x279C;  mydemo git:(master) &#x2717; go run "/Users/liuyue/wodfan/work/mydemo/hello.go"
ch1&#x4E2D;&#x53D6;&#x6570;&#x636E;&#x3002;&#x3002; 200
&#x279C;  mydemo git:(master) &#x2717; go run "/Users/liuyue/wodfan/work/mydemo/hello.go"
ch2&#x4E2D;&#x53D6;&#x6570;&#x636E;&#x3002;&#x3002; 200
&#x279C;  mydemo git:(master) &#x2717;

综上,Golang的通道其实就是将协程任务进行隔离,编写并发逻辑时,关注通道即可,说白了,Golang的通道就是Python多进程通信中的管道,Golang虽然没有显性的多进程调用,但其协程调度底层就是多进程之间的通信,因为只有多进程才可能利用CPU的多核资源。

Original: https://www.cnblogs.com/v3ucn/p/16640477.html
Author: 刘悦的技术博客
Title: 大道如青天,协程来通信,Go lang1.18入门精炼教程,由白丁入鸿儒,Go lang通道channel的使用EP14

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/516203/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • go更新腾讯云DNSPod的解析记录

    纯粹练手用的,大家轻喷 获取SecretId,SecretKey 打开腾讯云,登录之后打开 https://console.cloud.tencent.com/cam/capi,然…

    Go语言 2023年5月25日
    068
  • Go Error 嵌套到底是怎么实现的?

    原文链接: Go Error 嵌套到底是怎么实现的? Go Error 的设计哲学是 「Errors Are Values」。 这句话应该怎么理解呢?翻译起来挺难的。不过从源码的角…

    Go语言 2023年5月25日
    072
  • Golang 源码解读 01、深入解析 strings.Builder、strings.Join

    本文从我的《The Go Programming Language》学习笔记中分离出,单独成一篇文章方便查阅参考。 strings.Builder 源码解析 存在意义 使用 (st…

    Go语言 2023年5月25日
    082
  • Go语言之如何给*int32类型赋值

    直接上代码: package main import “fmt” func main () { var num *int32 var i int32 = 5…

    Go语言 2023年5月29日
    058
  • 字符集与编码

    一个比特(bit)可以是0,或者是1,8个比特(bit),组成一个字节(byte)。全为0时代表数字0,全为1时代表数字255。 一个字节可以表示256个数字,两个字节可以表示65…

    Go语言 2023年5月25日
    057
  • golang多版本管理工具

    前言 以往我安装 go环境都是去网站上下载对应文件,然后本地解压。每次发布新版本都这样做太麻烦了,所以我在寻找多版本管理工具。 [En] It’s too troubl…

    Go语言 2023年5月25日
    069
  • 盘点Go中的开发神器

    本文已收录 https://github.com/lkxiaolou/lkxiaolou 欢迎star。 在Java中,我们用Junit做单元测试,用JMH做性能基准测试(benc…

    Go语言 2023年5月25日
    083
  • 关于Golang的学习路线

    基础 安装golang环境Golang基础,流程控制,函数,方法,面向对象网络编程(自己做一个简单的tcp的聊天室,websocket,http,命令行工具)并发(可以看一下并发爬…

    Go语言 2023年5月25日
    069
  • 系统调用跟踪——分析(一)

    通过strace工具可跟踪用户进程与Linux内核的调用交互,可看到其中的System Call(系统调用)情况; &#x5B89;&#x88C5;strace&a…

    Go语言 2023年5月25日
    096
  • 使用 grpcurl 通过命令行访问 gRPC 服务

    如果环境不支持安装这种 GUI 客户端的话,那么有没有一种工具,类似于 curl 这样的,直接通过终端,在命令行发起请求呢? 答案肯定是有的,就是本文要介绍的 grpcurl。 首…

    Go语言 2023年5月25日
    085
  • golang拾遗:自定义类型和方法集

    golang拾遗主要是用来记录一些遗忘了的、平时从没注意过的golang相关知识。 很久没更新了,我们先以一个谜题开头练练手: package main import ( &quo…

    Go语言 2023年5月25日
    058
  • day2-变量与数据类型

    变量 概念:程序的基本组成单位 定义: 指定变量类型 根据值自行判断变量类型(类型推导) 省略var,定义赋值 var i int var i = 10 i, j := 20, 1…

    Go语言 2023年5月25日
    065
  • Go微服务框架-2.Go语言RPC编程实践

    Go语言实现RPC编程 上节课我们对RPC知识做了介绍,讲解了RPC的原理,通过图示方式讲解了RPC的内部执行过程。本节课,我们继续来学习RPC相关的内容。 在Go语言官方网站的p…

    Go语言 2023年5月29日
    068
  • 编译kubeadm使生成证书有效期为100年

    问题 编译 检查结果 问题 当我使用kubeadm部署成功k8s集群时在想默认生成的证书有效期是多久,如下所示 /etc/kubernetes/pki/apiserver.crt …

    Go语言 2023年5月25日
    062
  • GO语言 文件操作实例

    package main import ( "bufio" "fmt" "io/ioutil" "os&quo…

    Go语言 2023年5月29日
    056
  • 支持首次触发的 Go Ticker

    促使我写这篇文章主要是在写一个关于虚拟货币账户监控的项目时使用 Ticker 的问题。 Ticker 的问题 如果用过 Ticker 的朋友会知道,创建 Ticker 后并不会马上…

    Go语言 2023年5月25日
    076
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球