Golang 并发编程_go 语言取消并行

常见并发模型
  • 进程&线程 ( Apache )
    进程是一种系统运行行动, 就是代表计算机做某个事情的一系列行动的总和, 它是程序的执行实体, 一般情况下是一个程序一个进程, 多进程情况是一个程序多个进程
    线程是运算调度的最小单元, 它的作用就是运算, 由系统内核控制大小, 同时运行多个任务, 进程可以包含多个线程, 因此在同一个进程中, 可以执行多个线程, 每个线程负责一个动作
    系统最初的Web服务器都是基于进程&线程模型, 就是每新到一个请求就会分配一个进程或者线程, 每个进程只服务一个用户, 互联网初期用户的访问不多, 网站可以正常工作, 但是进程很昂贵, 一台服务器无法创建很多的进程, 随着互联网的发展, 网站越来越复杂, 一个页面可能就上百个请求, 操作系统就无法承受了
  • 异步非阻塞 ( Nginx, Libevent, NodeJS )
    一台服务器可以服务大量的用户, 并且资源消耗还很低, 但是其为了追求性能, 强行将线型的程序打乱, 开发和维护就变得很复杂, 调试也很困难
  • 协程 ( Golang, Erlang, Lua)
    协程 ( Coroutine ) 是轻量级的线程, 由用户来控制, 协程的内存消耗更小 ( 一个线程可以包含多个协程, 线程大约8MB的内存申请量, 协程大约2KB的内存申请量 ), 协程尚希文切换更快 ( 协程少一道手续, 线程申请内存需要走过内核, 协程申请内存不需要走过内核 )
    == Goroutine 也是一种协程, 它是在协程的基础上做了进一步优化, 并加入了Go语言的一些特性, 去掉了冗余的协程生命周期管理 ( 协程创建, 协程完成, 协程重用 ), 降低额外的延迟和开销 ( 由于协程间频繁交互导致的 ) 使得 Goroutine 更加高效也降低对系统的负担, 降低加锁/解锁的频率 ( 降低一部分额外的开销 )==
    降低了开发复杂度, 像写线型程序那样来书写全异步的程序, 其实协程底部就是线程, 但它比线程更轻量, 几十个协程体现在底层可能也就五六个线程, 协程可以理解为更高效更易用更轻量的线程
Golang 并发实现

多协程是指一段时间内协程的并行, 即某个任务使用多个协程同时进行处理, 多协程的必要条件: 协程任务之间有关联性 ( 相互之间组成整体任务, 相互之间有连续性 ), 有总分总的协调步骤过程
多协程任务步骤: 任务切分/分配, 启动多个协程, 合并多个协程的结果
多协程使用场景: 运算量比较多的流程上, 协程间依赖性比较弱
多协程的局限: 会增加额外的耗时, 会增加额外的内存消耗
协程等待: sync.WaitGroup
多协程生命周期: 协程的创建等全部生命历程的管理, 作用是为了便于协程的回收利用, 生命周期分类: 协程创建 ( 通过函数前加go关键字 ), 协程回收 ( Go语言的回收机制 ), 协程中断 ( Context 实现中断 )

package main

import (
	"context"
	"fmt"
	"sync"
)

// 协程等待
var wg sync.WaitGroup

// 主函数 主 Goroutine
func main() {

	// 初始化一个 context
	parent := context.Background()
	// 生成一个取消的 context
	ctx, cancel := context.WithCancel(parent)

	runTimes := 0
	wg.Add(1)
	// 启动 goroutine
	go func(ctx context.Context) {
		for {
			select {
			case <-ctx.Done():
				fmt.Println("Goroutine Done")
				return
			default:
				fmt.Println("Goroutine Running Times: ", runTimes)
				runTimes++
			}
			if runTimes >= 5 {
				cancel()
				wg.Done()
			}
		}

	}(ctx)

	wg.Wait()
}


  • 程序并发执行 ( goroutine ), 通过 goroutine 来保证程序的并发执行
foo() // 执行函数 foo, 程序等待函数 foo 返回

go foo() // 新建新的 goroutine 去执行函数 foo
bar() // 不用等待函数 foo 返回, 两个函数并发执行

  • 通过管道 channel 来实现多个 goroutine 间的数据同步和通信
    Channel 用于多个协程之间的通信
    Channel的妙用: 传递方面 ( 消息传递, 任务发送, 事件广播 ), 控制方面 ( 资源争抢, 并发控制, 流程开关 )
    Channel 关闭后, 可读不可写
    channel 在使用之前, 必须进行make初始化, 否则它是一个nil
    无缓冲区Channel, 使用时要同时具备输入和输出
    资源争抢应用场景: 电商的秒杀活动, 出行的司机抢单, 互金的股票抢购, 系统的计算资源争抢
package main

import (
	"context"
	"fmt"
	"sync"
	"time"
)

// 协程等待
var wg sync.WaitGroup

// 主函数 主 Goroutine
func main() {

	// 资源争抢, 100个人抢10个鸡蛋
	eggs := make(chan int, 10) // 设定Channel缓冲区, 根据业务场景需求, 设置适合大小

	// 超时 Context
	ctx, cancel := context.WithTimeout(context.Background(), 10\*time.Second)

	// 鸡蛋
	for i := 0; i < 10; i++ {
		eggs <- i
	}

	// close(eggs) 关闭后只读不可写, 用for range 可循环获取到通道内的值, 但是用for循环读取时, 即使通道已没有值, 也能获取到对应类型的零值, 一般 close 和 for range 搭配使用

	// 100个人并行抢
	for i := 0; i < 100; i++ {
		wg.Add(1)
		go func(n int, c context.Context) {
			// 多管道select调度
			select {
			case egg := <-eggs:
				fmt.Printf("people: %d get egg: %d\n", n, egg)
			case <-c.Done():
				fmt.Println("timeout")
				cancel()
				return
			default:
			}

			wg.Done()

		}(i, ctx)
	}

	wg.Wait()
}



// 初始化
c := make(chan string) // 创建一个通道 channel, 无缓冲区, 使用时要同时具备输入和输出, 即该管道要同时可写入和读取
go func (){
	time.Sleep(1 \* time.Second)
	// 输入
	c <- "message" // 发送消息到 channel
	// 关闭
	close(c)
}()
// 输出
msg := <- c // 阻塞直到接收到数据

  • 通过 select 在多个 channel 中选择数据读取或者写入
c1 := make(chan string, 1)
	c2 := make(chan string, 1)

	select {
	// c1 和 c2 都有值, 则随机其中之一执行
	case v := <-c1: // c1 管道有值则执行该条case
		fmt.Println("channel1 sends", v)
	case v := <-c2: // c2 管道有值则执行该条case
		fmt.Println("channel2 sends", v)
	default: // 可选
		fmt.Println("neither channel was ready")

	}


![img](https://img-blog.csdnimg.cn/img_convert/19813efce676500b30efc78490f0cb6b.png)
![img](https://img-blog.csdnimg.cn/img_convert/75a063c75b2d4f56c7f78f12a67f4d42.png)
![img](https://img-blog.csdnimg.cn/img_convert/b61c3450f6d4de1877c826c21196be46.png)

**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Go语言开发知识点,真正体系化!**


加入社区》https://bbs.csdn.net/forums/4304bb5a486d4c3ab8389e65ecb71ac0
664436191)]
[外链图片转存中...(img-K0JKymuk-1725664436191)]

**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Go语言开发知识点,真正体系化!**


加入社区》https://bbs.csdn.net/forums/4304bb5a486d4c3ab8389e65ecb71ac0
  • 17
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值