【Go实战基础】进程之间是使用什么通信的

目录

一、简介

二、数据结构

三、菜鸟实战

1、创建 g009.go

2、编译和运行

3、运行结果

一、简介

channel 是 Go中最核心的功能之一,因此理解 channel 的原理对于学习和使用 Go 非常重要。 channel 是 goroutine 之间通信的一种方式,可以类比成 Unix 中进程管道通信方式,channel 是支撑 Go 语言高性能并发编程模型的重要结构。

通道像一个传送带或者队列,总是遵循先进先出(First In First Out)的规则,保证收发数据的顺序。在任何时候,同时只能有一个 goroutine 访问通道进行发送和获取数据。

二、数据结构

// channel 数据结构
type hchan struct {
    qcount   uint           // 当前队列中剩余元素个数
    dataqsiz uint           // 环形队列长度,即可以存放的元素个数
    buf      unsafe.Pointer // 环形队列指针
    elemsize uint16         // 每个元素的大小
    closed   uint32         // 标识关闭状态
    elemtype *_type         // 元素类型
    sendx    uint           // 队列下标,指示元素写入时存放到队列中的位置
    recvx    uint           // 队列下标,指示元素从队列的该位置读出
    recvq    waitq          // 等待读消息的 goroutine 队列
    sendq    waitq          // 等待写消息的 goroutine 队列
    lock mutex              // 互斥锁,chan 不允许并发读写
}

三、菜鸟实战

实战需求:

用程序实现一个函数,原型为:void printNumber(int N),
内部创建三个线程 A、B、C,三个线程交替输出 1 到 N 之间的数字,
A 线程输出 1、4、7…,B 线程 2、5、8…,C 线程输出 3、6、9…,

马上安排!

1、创建 g009.go

/*
 * @Author: 菜鸟实战
 * @FilePath: /go110/go-009/g009.go
 * @Description: channel
 */

package main

import (
	"fmt"
	"runtime"
	"sync/atomic"
)

var index int32
var maxNum int32

// 开 ABC 三个channel 分别用于三个 channel 监听数据
var chA = make(chan int32)
var chB = make(chan int32)
var chC = make(chan int32)

// 监听关闭
var chClose = make(chan int32)

type Values struct {
	m map[string]string
}

func (v Values) Get(key string) string {
	return v.m[key]
}

func printNumber(N int) {
	//开三个协程做任务
	go printA(N)
	go printB(N)
	go printC(N)

	//给chA发数据通知它开始打印
	chA <- 1

	//等待
	<-chClose

	close(chA)
	close(chB)
	close(chC)
	close(chClose)

	fmt.Println("done")
}

func printA(N int) {
	//开始监听
	for {
		select {
		case v := <-chA:
			atomic.AddInt32(&index, 1)
			fmt.Print(v)
			fmt.Print("A,")
			chB <- v + 1 //通知B开始打印
			if v == maxNum {
				chClose <- 1
				return
			}
		case <-chClose:
			return
		}
	}

}

func printB(N int) {
	//B开始监听
	for {
		select {
		case v := <-chB:
			atomic.AddInt32(&index, 1)
			fmt.Print(v)
			fmt.Print("B,")
			chC <- v + 1 // 通知C开始打印

			if v == maxNum {
				chClose <- 1
				return
			}
		case <-chClose:
			return
		}
	}
}

func printC(N int) {
	//开始监听
	for {
		select {
		case v := <-chC:
			atomic.AddInt32(&index, 1)
			fmt.Print(v)
			fmt.Print("C,")
			chA <- v + 1 // 通过 channel 通知 A
			if v == maxNum {
				chClose <- 1
				return
			}
		case <-chClose:
			return
		}
	}
}

func main() {
	// 使用内置函数打印
	println("Hello", "菜鸟实战")

	index = 0
	maxNum = 20
	printNumber(20)

	// 当前版本
	fmt.Printf("版本: %s \n", runtime.Version())
}

2、编译和运行

# 1、生成模块依赖
go mod init g009
 
# 2、编译
go build g009.go 
 
# 3、编译后的目录结构
 
└── go-009
    ├── g009
    ├── g009.go
    └── go.mod
 
# 4、运行
go run g009

3、运行结果

Hello 菜鸟实战
1A,2B,3C,4A,5B,6C,7A,8B,9C,10A,11B,12C,13A,14B,15C,16A,17B,18C,19A,20B,done
21C,版本: go1.17.10 

  菜鸟实战,持续学习!

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

菜鸟实战

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值