GO语言协程创建使用并通过channel解决资源竞争

目录
  • 创建协程
  • 主协程终止,子协程也终止
  • runtime包
    • Gosched让出CPU时间片
    • Goexit立即结束当前协程
    • GOMAXPROCS设置并行CPU核数最大值,并返回之前的值
    • runtime.NumGoroutine()获取当前运行中的goroutine数量
  • 多任务资源竞争问题
  • 通过channel解决资源竞争问题
  • 主协程如何等其余协程完再退出

创建协程

goroutine是go的设计核心,就是协程
主协程终止了,子协程也终止

package main
import (
	"fmt"
	"time"
)
func newTask() {
	for {
		fmt.Println("this is a newTask")
		time.Sleep(time.Second) //延时1s
	}
}
func main() {
	go newTask() //新建一个协程, 新建一个任务
	for {
		fmt.Println("this is a main goroutine")
		time.Sleep(time.Second) //延时1s
	}
}

主协程终止,子协程也终止

package main
import (
	"fmt"
	"time"
)
//主协程退出了,其它子协程也要跟着退出
func main() {
	go func() {
		i := 0
		for {
			i++
			fmt.Println("子协程 i = ", i)
			time.Sleep(time.Second)
		}
	}() //别忘了()
	i := 0
	for {
		i++
		fmt.Println("main i = ", i)
		time.Sleep(time.Second)
		if i == 2 {
			break
		}
	}
}

runtime包

Gosched让出CPU时间片

等待其他协程执行完

runtime.Gosched()用于让出CPU时间片,让出当前goroutine(协程)的执行权限,调度器安排其他等待的任务运行,并在下次某个时候从该位置恢复执行。
类似:接力赛,A跑了一会碰到代码runtime.Gosched()就把接力棒交给B,A歇着,B继续跑

案例:

package main
import (
	"fmt"
	"runtime"
)
func main() {
	go func() {
		for i := 0; i < 5; i++ {
			fmt.Println("go")
		}
	}()
	for i := 0; i < 2; i++ {
		//让出时间片,先让别的协议执行,它执行完,再回来执行此协程
		runtime.Gosched()
		fmt.Println("hello")
	}
}

go
go
go
go
go
hello
hello

Goexit立即结束当前协程

runtime.Goexit()  //立即结束当前协程

案例:

package main
import (
	"fmt"
	"runtime"
)
func test() {
	defer fmt.Println("ccccccccccccc")
	//return //终止此函数
	runtime.Goexit() //终止所在的协程
	fmt.Println("dddddddddddddddddddddd")
}
func main() {
	//创建新建的协程
	go func() {
		fmt.Println("aaaaaaaaaaaaaaaaaa")

		//调用了别的函数
		test()
		fmt.Println("bbbbbbbbbbbbbbbbbbb")
	}() //别忘了()
	//特地写一个死循环,目的不让主协程结束
	for {
	}
}
aaaaaaaaaaaaaaaaaa
ccccccccccccc

GOMAXPROCS设置并行CPU核数最大值,并返回之前的值

runtime.GOMAXPROCS() //设置并行CPU核数最大值,并返回之前的值
package main
import (
	"fmt"
	"runtime"
)
func main() {
	//n := runtime.GOMAXPROCS(1) //指定以1核运算
	n := runtime.GOMAXPROCS(2) //指定以8核运算
	fmt.Println("n = ", n)
	for {
		go fmt.Print(1)
		fmt.Print(0)
	}
}

runtime.NumGoroutine()获取当前运行中的goroutine数量

先介绍一个最简单的监控方式。

通过 runtime.NumGoroutine() 获取当前运行中的 goroutine 数量,通过它确认是否发生泄漏。

func main() {
 go test()
 go test()
 go test()
 go test()
 a:=runtime.NumGoroutine()
 fmt.Println(a) // 5
 for  {
 }
}

多任务资源竞争问题

package main
import (
	"fmt"
	"time"
)
//定义一个打印机,参数为字符串,按每个字符打印
//打印机属于公共资源
func Printer(str string) {
	for _, data := range str {
		fmt.Printf("%c", data)
		time.Sleep(time.Second)
	}
	fmt.Printf("\n")
}
func person1() {
	Printer("hello")
}
func person2() {
	Printer("world")
}
func main() {
	//新建2个协程,代表2个人,2个人同时使用打印机
	go person1()
	go person2()
	//特地不让主协程结束,死循环
	for {
	}
}

通过channel解决资源竞争问题

package main
import (
	"fmt"
	"time"
)
//全局变量,创建一个channel
var ch = make(chan int)
//定义一个打印机,参数为字符串,按每个字符打印
//打印机属于公共资源
func Printer(str string) {
	for _, data := range str {
		fmt.Printf("%c", data)
		time.Sleep(time.Second)
	}
	fmt.Printf("\n")
}
//person1执行完后,才能到person2执行
func person1() {
	Printer("hello")
	ch <- 666 //给管道写数据,发送
}
func person2() {
	<-ch //从管道取数据,接收,如果通道没有数据他就会阻塞
	Printer("world")
}
func main() {
	//新建2个协程,代表2个人,2个人同时使用打印机
	go person1()
	go person2()
	//特地不让主协程结束,死循环
	for {
	}
}

主协程如何等其余协程完再退出

var wg sync.WaitGroup
wg.Add(2)  //任务数
wg.Done() //结束
wg.Wait() //等待
package main
import (
	"fmt"
	"sync"
)
var wg sync.WaitGroup
func main() {
	wg.Add(2)
	out := producer()
	consumer(out)
	defer fmt.Println("主线程结束")
	wg.Wait()  //等待
}
//此通道只能写,不能读
func producer() chan interface{} {
	ch := make(chan interface{})
	go func() {
		for i := 0; i < 5; i++ {
			ch <- fmt.Sprintf("协程1-%d", i) //写入字符串
		}
		defer close(ch)
		wg.Done()  //结束
	}()
	return ch
}
//此channel只能读,不能写
func consumer(data chan interface{}) {
	defer fmt.Println("读取结束")
	go func() {
		for num := range data {
			fmt.Println(num)
		}
		wg.Done() //结束
	}()
}

以上就是GO语言协程创建使用并通过channel解决资源竞争的详细内容,更多关于GO语言协程channel解决资源竞争的资料请关注我们其它相关文章!

(0)

相关推荐

  • Go缓冲channel和非缓冲channel的区别说明

    在看本篇文章前我们需要了解阻塞的概念 在执行过程中暂停,以等待某个条件的触发 ,我们就称之为阻塞 在Go中我们make一个channel有两种方式,分别是有缓冲的和没缓冲的 缓冲channel 即 buffer channel 创建方式为 make(chan TYPE,SIZE) 如 make(chan int,3) 就是创建一个int类型,缓冲大小为3的 channel 非缓冲channel 即 unbuffer channel 创建方式为 make(chan TYPE) 如 make(cha

  • Go并发控制Channel使用场景分析

    1. 前言 channel一个类型管道,通过它可以在goroutine之间发送和接收消息.它是Golang在语言层面提供的goroutine间的通信方式. Channel是Go中的一个核心类型,你可以把它看成一个管道,通过它并发核心单元就可以发送或者接收数据进行通讯(communication). 它的操作符是箭头 <- . 我们考虑这么一种场景,协程A执行过程中需要创建子协程A1.A2.A3-An,协程A创建完子协程后就等待子协程退出. 针对这种场景,GO提供了三种解决方案: Channel:

  • Go语言中的通道channel详情

    目录 一.Go语言通道基础概念 1.channel产生背景 2.channel工作方式 二.通道使用语法 1.通道的声明与初始化 2.将数据放入通道内 3.从通道内取出数据 4.关闭通道close 三.单项通道及通道的状态分析 1.单项输出通道 2.单项输入通道 3.通道的状态 四.通道死锁原因分析 一.Go语言通道基础概念 1.channel产生背景 线程之间进行通信的时候,会因为资源的争夺而产生竟态问题,为了保证数据交换的正确性,必须使用互斥量给内存进行加锁,go语言并发的模型是CSP,提倡

  • Go中Channel发送和接收操作指南

    目录 前言 一.Channel的定义 二.Channel的操作 三.Channel发送和接收操作的特点 四.Channel的类型 五.Channel的源码学习 总结 前言 先来看一道面试题: 对已经关闭的 chan 进行读写,会怎么样?为什么? 在上一篇学习 Go 协程的文章中,知道 go 关键字可以用来开启一个 goroutine 进行任务处理,但多个任务之间如果需要通信,就需要用到通道(channel)了. 一.Channel的定义 声明并初始化一个通道,可以使用 Go 语言的内建函数 ma

  • Go语言的Channel遍历方法详解

    先来看看基本的定义: channel是Go语言中的一个核心类型,可以把它看成管道.并发核心单元通过它就可以发送或者接收数据进行通讯,这在一定程度上又进一步降低了编程的难度. channel是一个数据类型,主要用来解决go程的同步问题以及协程之间数据共享(数据传递)的问题. (1)channle 本质上是一个数据结构--(队列),数据是先进先出. (2)具有线程安全机制,多个go程访问时,不需要枷锁,也就是说channel本身是线程安全的. (3)channel是有类型的,如一个string类型的

  • Golang中channel的原理解读(推荐)

    数据结构 channel的数据结构在$GOROOT/src/runtime/chan.go文件下: type hchan struct { qcount uint // 当前队列中剩余元素个数 dataqsiz uint // 环形队列长度,即可以存放的元素个数 buf unsafe.Pointer // 环形队列指针 elemsize uint16 // 每个元素的大小 closed uint32 // 标记是否关闭 elemtype *_type // 元素类型 sendx uint //

  • GO语言协程创建使用并通过channel解决资源竞争

    目录 创建协程 主协程终止,子协程也终止 runtime包 Gosched让出CPU时间片 Goexit立即结束当前协程 GOMAXPROCS设置并行CPU核数最大值,并返回之前的值 runtime.NumGoroutine()获取当前运行中的goroutine数量 多任务资源竞争问题 通过channel解决资源竞争问题 主协程如何等其余协程完再退出 创建协程 goroutine是go的设计核心,就是协程主协程终止了,子协程也终止 package main import ( "fmt"

  • Go语言协程处理数据有哪些问题

    目录 前言 一.Goroutine 二.sync.WaitGroup 三.数据排序 四.限制协程数 五.协程Panic处理 总结 前言 我们在开发后台项目常常会遇到一个情况,功能模块列表数据导出Excel功能,但列表中某个字段无法通过Sql联表查询,且一次性查询再匹对也不方便:此时对列表数据循环,再一个个查询结果加入列表,势必需要很长的时间,我们该怎么才能提升下载速度呢? (这里采用Go开发服务端) 一.Goroutine 当然第一个想到可能是采用协程处理循环里面要查询的数据 type Card

  • GO语言协程互斥锁Mutex和读写锁RWMutex用法实例详解

    sync.Mutex Go中使用sync.Mutex类型实现mutex(排他锁.互斥锁).在源代码的sync/mutex.go文件中,有如下定义: // A Mutex is a mutual exclusion lock. // The zero value for a Mutex is an unlocked mutex. // // A Mutex must not be copied after first use. type Mutex struct { state int32 sem

  • go语言中的协程详解

    协程的特点 1.该任务的业务代码主动要求切换,即主动让出执行权限 2.发生了IO,导致执行阻塞(使用channel让协程阻塞) 与线程本质的不同 C#.java中我们执行多个线程,是通过时间片切换来进行的,要知道进行切换,程序需要保存上下文等信息,是比较消耗性能的 GO语言中的协程,没有上面这种切换,一定是通过协程主动放出权限,不是被动的. 例如: C# 中创建两个线程 可以看到1和2是交替执行的 Go语言中用协程实现一下 runtime.GOMAXPROCS(1) 这个结果就是 执行了1 在执

  • Kotlin中协程的创建过程详析

    目录 为什么需要协程? 创建并启动协程 协程的执行过程 suspend block 是如何变为协程体被执行的? 总结 总结 为什么需要协程? 协程可以简化异步编程,可以顺序地表达程序,协程也提供了一种避免阻塞线程并用更廉价.更可控的操作替代线程阻塞的方法 – 挂起函数. Kotlin 的协程是依靠编译器实现的, 并不需要操作系统和硬件的支持.编译器为了让开发者编写代码更简单方便, 提供了一些关键字(例如suspend), 并在内部自动生成了一些支持型的代码. 创建并启动协程 fun create

  • Kotlin协程Dispatchers原理示例详解

    目录 前置知识 demo startCoroutineCancellable intercepted()函数 DefaultScheduler中找dispatch函数 Runnable传入 Worker线程执行逻辑 小结 前置知识 Kotlin协程不是什么空中阁楼,Kotlin源代码会被编译成class字节码文件,最终会运行到虚拟机中.所以从本质上讲,Kotlin和Java是类似的,都是可以编译产生class的语言,但最终还是会受到虚拟机的限制,它们的代码最终会在虚拟机上的某个线程上被执行. 之

  • 一文详解go同步协程的必备工具WaitGroup

    目录 1. 简介 2. 基本使用 2.1 定义 2.2 使用方式 2.3 使用例子 3.实现原理 3.1 设计初衷 3.2 基本原理 3.3 代码实现 3.3.1 Add方法 3.3.2 Done方法实现 3.3.3 Wait方法实现 3.4 实现补充 4.使用注意事项 4.1 Add方法和Done方法需要成对出现 4.2 在所有任务都已经添加之后,才调用Wait方法进行等待 5. WaitGroup常见使用场景 总结 1. 简介 本文将介绍 Go 语言中的 WaitGroup 并发原语,包括

  • 浅谈go 协程的使用陷阱

    golang 语言协程 协程中使用全局变量.局部变量.指针.map.切片等作为参数时需要注意,此变量的值变化问题. 与for 循环,搭配使用更需谨慎. 1.内置函数时直接使用局部变量,未进行参数传递 func main() { for i := 0; i < 100; i++ { go func() { fmt.Println(i) }() } } 运行效果 func main() { for i := 0; i < 100; i++ { go func(i int) { fmt.Printl

  • Java协程编程之Loom项目实战记录

    目录 前提 Loom项目简单介绍 Virtual Thread使用 小结 前提 之前很长一段时间关注JDK协程库的开发进度,但是前一段时间比较忙很少去查看OpenJDK官网的内容.Java协程项目Loom(因为项目还在开发阶段,OpenJDK给出的官网https://openjdk.java.net/projects/loom中只有少量Loom项目相关的信息)已经在2018年之前立项,目前已经发布过基于JDK17编译和JDK18编译等早期版本,笔者在下载Loom早期版本的时候只找到JDK18编译

  • Java协程编程之Loom

    目录 Java协程编程Loom 1.Loom项目简单介绍 2.Virtual Thread使用 Java协程编程Loom 前提: OpenJDK给出的官网https://openjdk.java.net/projects/loom有少量Loom项目相关的信息)JDK17编译和JDK18编译等早期版本,Loom早期版本JDK18编译的版本:下载入口在:https://jdk.java.net/loom 由于该JDK版本过高,目前可以使用主流IDE导入Loom-JDK-18+9进行代码高亮和语法提醒

随机推荐