首页 > 其他分享 >Golang学习之路6-goroutine并发

Golang学习之路6-goroutine并发

时间:2022-11-19 09:22:41浏览次数:48  
标签:fmt goroutine Golang 并发 管道 func time go

@

目录


前言

什么是 goroutine?简称可以使:go程、并发

  • goroutine是与其他函数或方法同时运行的函数或方法。
  • goroutine可以被认为是轻量级线程,天生支持多并发。
  • 与线程相比,创建goroutine的成本很小,因此Go 应用程序通常会同时运行数千个goroutine。

一、goroutine用法

go语言天生支持多并发,使用方式:

  • 方式一:go func()
  • 方式二(匿名):go func(){}()
package main
import (
	"fmt"
	"time"
)
func display(count int) {
	for {
		fmt.Println("这是子go程======>:", count)
		time.Sleep(1)
		count++
	}
}

func main() {
	go display(1)

	// 匿名 子go程 函数
	//go func () {
	//	count := 1
	//	for {
	//		fmt.Println("这是子go程======>:", count)
	//		time.Sleep(1)
	//		count++
	//	}
	//}()
	
	// 主go程
	count := 1
	for {
		fmt.Println("这是主go程:", count)
		count++
		time.Sleep(1)
		if count > 2 {
			break
		}
	}
}

可以看到,主进程没有打印第3次,而子进程打印了第3次
在这里插入图片描述

二、goroutine循环

比如起3个进程跑goroutine,cpu资源会被竞争不确定谁先谁后:

for i := 0; i <= 3; i++ {
	go func() {}()
}

三、goroutine提前退出

三种退出go程方式:

  • return:只退出当前子go程函数
  • runtime.Goexit():只退出当前go程
  • os.Exit(-1):退出所以的主子go程
package main

import (
	"fmt"
	"os"
	"time"
)

func main() {
	go func() {
		func() {
			fmt.Println("这是子go程 内部函数111")
			//return 			  // 只结束此函数,会执行到:子go程222
			//runtime.Goexit()    // 退出当前go程,不会执行到:子go程222
			os.Exit(-1)	          // 退出所以主子进程
		}()
		fmt.Println("子go程222")
	}()
	time.Sleep(1)
	fmt.Println("结束主go程!")
}

四、goroutine双向管道

通道可用于两个 goroutine 之间通过传递一个指定类型的值来同步运行和通讯。操作符 <- 用于指定通道的方向,发送或接收。如果未指定方向,则为双向通道。

ch <- value    // 把 value  发送到通道 ch
value := <-ch  // 从 ch 接收数据,并把值赋给 value 

chan双向管道:

  • 使用通讯时不需要上锁解锁;
  • 未创建容量时是无缓冲的,反之是有缓冲的;
  • 当缓冲区写满时或读取完成时会阻塞,当被读取后再恢复写入;
  • 管道的读与写次数必须对等,否则会被堵塞,①如果阻塞主go程那么程序被锁死至崩溃,②如果阻塞在子go程会出现内存泄漏;
  • 需要使用make分配空间,否则管道默认是nil,读写都会堵塞(和map一样所以建议都是make);
  • 使用goroutine管道时推荐使用for range,当管道写入完成后应关闭close(chan)
package main
import (
	"fmt"
	"time"
)

func main() {
	// 创建一个容量为10的int有缓冲管道
	numChan := make(chan int, 10)

	// 写“管道”数据
	go func() {
		for i := 1; i < 21; i++ {
			numChan <- i
			fmt.Println("11-->子go程写入数据:", i)
		}
		// 写入结束,关闭管道
		close(numChan)
	}()

	// 读“管道”数据
	go func() {
		for num := range numChan {
			fmt.Println("22-->子go程读取数据data:", num)
		}
	}()

	time.Sleep(1 * time.Second)

	// 判断管道是否关闭
	for {
		v, ok := <-numChan
		if !ok {
			fmt.Println("管道已经关闭,准备退出!!")
			break
		}
		fmt.Println("v:", v)
	}
}

五、goroutine单向管道

一般用于函数参数,比如只读、只写单向管道,看看下面和双向管道有何区别?
生产者:chan<-
消费者:<-chan
双向管道时都是:<-numChan

package main
import (
	"fmt"
	"time"
)

// 生产者:只写入数据
func producer(out chan<- int) {
	for i := 1; i < 11; i++ {
		out <- i
		fmt.Println("写入数据:", i)
	}
	close(out)
}

// 消费者:只读数据
func consumer(in <-chan int) {
	for v := range in {
		fmt.Println("读取数据:", v)
	}
}

func main() {
	// 创建一个双向通道
	numChan := make(chan int, 5)

	// 创建生产者
	go producer(numChan)

	// 创建消费者
	go consumer(numChan)

	time.Sleep(200)
}

在这里插入图片描述

六、监听管道

在多go程并发时,我们可以通过select进行监听到对应数据,突然觉得类似消息事件一样,一个负责推、一个负责监听...
select:监听多管道 (写入/读写数据、关闭管道)

package main
import (
	"fmt"
	"time"
)

func main() {
	// 创建两个管道,用来测试监听
	chan1 := make(chan int)
	chan2 := make(chan int)
	// 监听go程
	go func() {
		for {
			select {
			case data1 := <-chan1:
				fmt.Println("监听到chan111:", data1)
			case data2 := <-chan2:
				fmt.Println("监听到chan222:", data2)
			default:
				fmt.Println("正常监听中...")
				time.Sleep(2 * time.Second)
			}
		}
	}()

	// go程:两个管道分别写入数据
	go func() {
		for i := 0; i < 5; i++ {
			chan1 <- i
			i++
			chan2 <- i
		}
	}()

	count := 1
	for {
		time.Sleep(10 * time.Second)
		if count == 6 {
			break
		}
		count++
	}
}

如下图,可以看到当我们监听到有写入数据时会得到对应的类型数据,当没有写入时 default 一直在负责监听!
在这里插入图片描述

总结

以上就是今天学习的内容,本文仅仅简单介绍了goroutine的使用,而在项目中如何实践还请大家多多查阅资料了解!

标签:fmt,goroutine,Golang,并发,管道,func,time,go
From: https://www.cnblogs.com/gsxl/p/16890937.html

相关文章

  • Golang 学习笔记
    基础语法只记录需要特别注意的点Diff变量声明未使用会CE。_的妙用交换变量:a,b=b,a空白标识符_用于抛弃值,如值5在:_,b=5,7中被抛弃。_实际上是一......
  • 并发编程(部分讲解)
    同步、异步、阻塞、非阻塞概念前言在实际的开发中,经常会听到同步,异步,阻塞,非阻塞这些编程概念,每次遇到的时候都会蒙圈,尤其是在一些场景下同步与阻塞,异步与非阻塞感觉没啥......
  • 并发编程
    并发编程同步与异步用来表达任务的提交方式同步提交完任务之后原地等待任务的返回结果期间不做任何事可靠任务序列异步提交完任务后不等待任务的返回结果直接去......
  • 并发编程
    内容概要并发编程理论与操作系统发展史多道技术近程理论及调度算法内容概要同步与异步阻塞与非阻塞创建进程的两种方式进程join方法进程间数据隔......
  • 网络编程与并发
    今日内容同步与异步用来表达任务的提交方式同步 提交完任务之后原地等待人物的返回结果期间不做任何事异步 提交完任务之后不原地等待任务的返回结果直接去做其......
  • 08.大促高并发系统下JVM如何调优指导(4)
                                                         ......
  • 网络并发1
    今日内容详细同步与异步用来表达任务的提交方式同步 提交完任务之后原地等待任务的返回结果期间不做任何事异步 提交完任务之后不原地等待任务的返回结果直接去做......
  • 并发编程1
    今日内容概要同步与异步阻塞与非阻塞创建进程的多种方式进程间的数据隔离进程的join方法IPC机制生产者与消费者模型进程对象的多种方法守护进程僵尸进程与孤儿......
  • Pthread 并发编程(三)——深入理解线程取消机制
    Pthread并发编程(三)——深入理解线程取消机制基本介绍线程取消机制是pthread给我们提供的一种用于取消线程执行的一种机制,这种机制是在线程内部实现的,仅仅能够在共享内......
  • golang分层测试之http接口测试入门教程
    前言前几话主要讲解关于使用golang进行单元测试,在单元测试的上一层就是接口测试,本节主要讲使用golang进行接口测试,其中主要以http协议的接口测试来讲解golang中的http请......