Go 协程(goroutine)与通道(channel)

本文深入探讨Go语言的协程(goroutine)和通道(channel),包括WaitGroup、并发与并行的区别、指定核心数量、无缓冲与带缓冲通道、信号量模式、通道工厂模式、选择器、计时器、恢复(recover)、锁与通道的选择、Futures模式、链式协程以及并行处理大量数据的策略,并提供了基准测试的介绍。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

协程

package main

import "time"

func main() {
   
	go say("Hello World")

	// 没有下一行,则主线程都结束了协程还没打印完说不定
	time.Sleep(time.Second * 1)
}

func say(s string) {
   
	println(s)
}

2.WaitGroup

package main

import (
	"sync"
)

// 协程队列
var wg = sync.WaitGroup{
   }
func main() {
   
	// 加入队列
	wg.Add(1)
	go say("Hello World")
	// 告诉主线程等一下,等协程都执行完了在退出
	wg.Wait()
}

func say(s string) {
   
	println(s)
	// 协程处理完毕 相当于 wg.Add(-1)
	wg.Done()
}

同时启动多个协程的时候

package main

import (
	"strconv"
	"sync"
)

// 协程队列
var wg = sync.WaitGroup{
   }
func main() {
   
	// 加入队列
	wg.Add(5)
	for i := 0; i < 5; i++ {
   
		go say("Hello World" + strconv.Itoa(i))
	}

	// 告诉主线程等一下,等协程都执行完了在退出
	wg.Wait()
}

func say(s string) {
   
	println(s)
	// 协程处理完毕
	wg.Done()
}

看上去像是“同时执行”,其实这只是并发
在这里插入图片描述

并发 并行 核心数量

并发:单核CPU。同一时间只能执行一个程序,但是CPU却可以在不同程序之间快速切换
并行:多核CPU。CPU分别处理不同程序,一起执行。

// 设置核心数,模拟单核
runtime.GOMAXPROCS(1)

对于 n 个核心的情况设置 GOMAXPROCS 为 n-1 以获得最佳性能,也同样需要遵守这条规则:协程的数量 > 1 + GOMAXPROCS > 1。

用命令行指定使用的核心数量

使用 flags 包,如下:

var numCores = flag.Int("n", 2, "number of CPU cores to use")

在 main() 中:

flag.Parse()
runtime.GOMAXPROCS(*numCores)

channel

协程之间通信的渠道,消息队列
数据在通道中进行传递:在任何给定时间,一个数据被设计为只有一个协程可以对其访问,所以不会发生数据竞争。 数据的所有权(可以读写数据的能力)也因此被传递。
通常使用这样的格式来声明通道:var identifier chan datatype

  • 未初始化的通道的值是nil。
  • 只能传输一种类型的数据,比如 chan int 或者 chan string,所有的类型都可以用于通道,空接口 interface{}也可以。甚至可以(有时非常有用)创建通道的通道。
  • 引用类型,使用make创建
  • 先进先出(FIFO)的结构保证顺序

<-

流向通道

ch <- int1

从通道流出(三种)

int2 := <- ch	int2未声明
int3 = <- ch	int3已声明

// 单独调用获取通道的(下一个)值,当前值会被丢弃,但是可以用来验证
if <- ch == 200 {
   

}

Eg:

package main

import (
	"fmt"
	"time"
)

func main() {
   
	var ch = make(chan string)
	go add(ch)
	go delete(ch)
	time.Sleep(time.Second * 1)
}

func add(ch chan string) {
   
	ch <- "a"
	ch <- "b"
	ch <- "c"
}

func delete(ch chan string) {
   
	var c string
	for {
   
		c = <- ch
		fmt.Println(c)
	}
}

通道阻塞

需求,把输出结果返回给主线程:

package main

import "strconv"

func main() {
   
	var result = make(chan string)
	for i 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值