Go routine使用方法讲解

 更新时间:2023年01月09日 11:54:28   作者:鲲鹏飞九万里  
goroutine是Go语言提供的语言级别的轻量级线程,在我们需要使用并发时,我们只需要通过go关键字来开启goroutine即可。这篇文章主要介绍了GoLang并发机制goroutine原理,感兴趣的可以了解一下

一、怎么才能让主goroutine等待其它goroutine

方法一:让主goroutine "sleep"一段时间

func main() {
	for i := 0; i < 10; i++ {
		go func(i int) {
			fmt.Println(i)
		}(i)
	}
	time.Sleep(time.Microsecond * 100)
}

缺点是:睡眠的时间很难把握。

方法二:使用通道,使用chan struct{}类型

func main() {
	num := 10
	var ch = make(chan struct{}, num)
	for i := 0; i < num; i++ {
		go func(i int) {
			fmt.Println(i)
			ch <- struct{}{}
		}(i)
	}
	for i := 0; i < num; i++ {
		<-ch
	}
}

类型字面量struct{}有些类似空接口类型interface{},它代表了即不包含任何字段也不拥有任何方法的空结构体类型。

struct{}类型值的表示法只有一个,即:struct{}{}。并且它占用的内存空间是0字节,确切地说,这个值在整个GO程序中永远都只会存在一份。

方法三:使用sync.WaitGroup

待补充。

二、怎么让多个goroutine按照既定的顺序运行

package main
import (
	"fmt"
	"sync/atomic"
	"time"
)
func main() {
	num := uint32(100)
	var count uint32 = 0
	trigger := func(i uint32, fn func()) {
		for {
			if atomic.LoadUint32(&count) == i {
				fn()
				atomic.AddUint32(&count, 1)
				break
			}
			// 这里加Sleep语句是很有必要的
			time.Sleep(time.Microsecond)
		}
	}
	for i := uint32(0); i < num; i++ {
		go func(i uint32) {
			fn := func() {
				fmt.Println(i)
			}
			trigger(i, fn)
		}(i)
	}
	trigger(num, func() {})
}

这里的trigger函数实现了一种自旋(spining)。

上面的自旋中添加了time.Sleep(time.Microsecond)语句:

这主要是因为:Go 调度器在需要的时候只会对正在运行的 goroutine 发出通知,试图让它停下来。但是,它却不会也不能强行让一个 goroutine 停下来。

所以,如果一条 for 语句过于简单的话,比如这里的 for 语句就很简单(因为里面只有一条 if 语句),那么当前的 goroutine 就可能不会去正常响应(或者说没有机会响应)Go 调度器的停止通知。

因此,这里加一个 sleep 是为了:在任何情况下(如任何版本的 Go、任何计算平台下的 Go、任何的 CPU 核心数等),内含这条 for 语句的这些 goroutine 都能够正常地响应停止通知。

不加Sleep语句,可能会导致一直抢占不到资源,也就没有机会运行,就可能会导致程序一直运行,不会终止。

乐观锁:总是假设在“我”操作共享资源的过程中没有“其他人”竞争操作。如果发现“其他人”确实在此期间竞争了,也就是发现假设失败,那就等一等再操作。CAS原子操作基本上能够体现出这种思想。通常,低频的并发操作适合用乐观锁。乐观锁一般会用比较轻量级的同步方法(如原子操作),但也不是100%。注意,高频的操作用乐观锁的话反而有可能影响性能,因为多了一步“探查是否有人与我竞争”的操作(当然了,标准的CAS操作可以把这种影响降到最低)。

悲观锁:总是假设在“我”操作共享资源的过程中一定有“其他人”竞争操作。所以“我”会先用某种同步方法(如互斥锁)保护我的操作。这样的话,“我”在将要操作的时候就没必要去探查是否有人与我竞争(因为“我”总是假设肯定有竞争,而且已经做好了保护)。通常,频次较高的并发操作适合用悲观锁。不过,如果并发操作的频次非常低,用悲观锁也是可以的,因为这种情况下对性能影响不大。

最后,一定要注意,使用任何同步方法和异步方法都首先要考虑程序的正确性,并且还要考虑程序的性能。程序的正确性一定要靠功能测试来保障,程序的性能一定要靠性能测试来保障。

到此这篇关于Go routine使用方法讲解的文章就介绍到这了,更多相关Go routine内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 通过Golang编写一个AES加密解密工具

    通过Golang编写一个AES加密解密工具

    这篇文章主要为大家详细介绍了如何利用Golang制作一个AES加密解密工具,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下
    2022-05-05
  • golang抓取网页并分析页面包含的链接方法

    golang抓取网页并分析页面包含的链接方法

    今天小编就为大家分享一篇golang抓取网页并分析页面包含的链接方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2019-08-08
  • 使用go实现删除sql里面的注释和字符串功能(demo)

    使用go实现删除sql里面的注释和字符串功能(demo)

    这篇文章主要介绍了使用go实现删除sql里面的注释和字符串功能,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-11-11
  • Go语言中反射的正确使用

    Go语言中反射的正确使用

    Go本身不支持模板,因此在以往需要使用模板的场景下往往就需要使用反射(reflect). 反射使用多了以后会容易上瘾,有些人甚至会形成一种莫名其妙的鄙视链。下面这篇文章就给大家介绍了如何正确使用Go语言中的反射以及在使用前的注意,有需要的朋友们下面来一起看看吧。
    2016-12-12
  • 浅析Golang中的内存逃逸

    浅析Golang中的内存逃逸

    内存逃逸分析是go的编译器在编译期间,根据变量的类型和作用域,确定变量是堆上还是栈上。本文将通过示例浅析一下Golang中的内存逃逸,需要的可以了解一下
    2022-10-10
  • 解决go 生成的exe不在bin文件夹里的问题

    解决go 生成的exe不在bin文件夹里的问题

    这篇文章主要介绍了解决go 生成的exe不在bin文件夹里的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-12-12
  • go语言中的return语句

    go语言中的return语句

    这篇文章主要介绍了go语言中的return语句,文章围绕主题展开详细的内容介绍,具有一定的参考价值,需要的小伙伴可以参考一下,希望对你的学习有所帮助
    2022-05-05
  • 详解Golang的GC三色标记法

    详解Golang的GC三色标记法

    这篇文章主要为大家介绍了Golang的GC三色标记法,文中有详细的实现过程供大家参考,对大家的学习或工作有一定帮助,感兴趣的可以跟着小编一来看看
    2023-05-05
  • 线上问题排查之golang使用json进行对象copy

    线上问题排查之golang使用json进行对象copy

    这篇文章主要介绍了线上问题排查之golang使用json进行对象copy,文章围绕golang使用json进行对象copy的内存溢出问题排查展开详细内容需要的小伙伴可以参考一下
    2022-06-06
  • Golang比较两个slice是否相等的问题

    Golang比较两个slice是否相等的问题

    本文主要介绍了Golang比较两个slice是否相等的问题,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-03-03

最新评论