zoukankan      html  css  js  c++  java
  • 【go语言学习】并发实现

    一、什么是goroutine

    Goroutine是Go语言特有的名词。区别于进程Process,线程Thread,协程Coroutine,因为Go语言的创造者们觉得和他们是有所区别的,所以专门创造了Goroutine。

    Goroutine是与其他函数或方法同时运行的函数或方法。Goroutines可以被认为是轻量级的线程。与线程相比,创建Goroutine的成本很小,它就是一段代码,一个函数入口。以及在堆上为其分配的一个堆栈(初始大小为4K,会随着程序的执行自动增长删除)。因此它非常廉价,Go应用程序可以并发运行数千个Goroutines。

    二、主goroutine

    封装main函数的goroutine称为主goroutine。
    主goroutine所做的事情并不是执行main函数那么简单。它首先要做的是:设定每一个goroutine所能申请的栈空间的最大尺寸。在32位的计算机系统中此最大尺寸为250MB,而在64位的计算机系统中此尺寸为1GB。如果有某个goroutine的栈空间尺寸大于这个限制,那么运行时系统就会引发一个栈溢出(stack overflow)的运行时恐慌。随后,这个go程序的运行也会终止。

    此后,主goroutine会进行一系列的初始化工作,涉及的工作内容大致如下:

    • 创建一个特殊的defer语句,用于在主goroutine退出时做必要的善后处理。因为主goroutine也可能非正常的结束
    • 启动专用于在后台清扫内存垃圾的goroutine,并设置GC可用的标识
    • 执行mian包中的init函数
    • 执行main函数
    • 执行完main函数后,它还会检查主goroutine是否引发了运行时恐慌,并进行必要的处理。最后主goroutine会结束自己以及当前进程的运行。

    三、如何使用goroutine

    Go语言中使用goroutine非常简单,只需要在调用函数的时候在前面加上go关键字,就可以为一个函数创建一个goroutine。

    一个goroutine必定对应一个函数,可以创建多个goroutine去执行相同的函数。

    package main
    
    import (
    	"fmt"
    )
    
    func main() {
    	go f1()
    	fmt.Println("你好,世界")
    }
    
    func f1() {
    	fmt.Println("hello world")
    }
    

    运行结果

    你好,世界
    

    或者

    hello world
    你好,世界
    

    多次运行以上程序,会出现不同的输出结果。
    这是因为:上面的程序有main函数主goroutine,和f1函数子goroutine。程序运行时,当子goroutine优先抢到系统资源,就会输出hello world,然后主goroutine输出你好,世界,结束程序;当主goroutine优先抢到系统资源,就会输出你好,世界,然后主goroutine就结束了,所有在main()函数中启动的goroutine会一同结束。

    修改以上代码:

    package main
    
    import (
    	"fmt"
    	"time"
    )
    
    func main() {
    	go f1()
    	fmt.Println("你好,世界")
    	time.Sleep(1 * time.Second)
    }
    
    func f1() {
    	fmt.Println("hello world")
    }
    
    

    运行结果

    你好,世界
    hello world
    

    增加了主goroutine睡眠1s,这样子goroutine有足够的时间来执行。

    四、启动多个goroutine

    package main
    
    import (
    	"fmt"
    	"time"
    )
    
    func main() {
    	go numbers()
    	go alphabets()
    	time.Sleep(3000 * time.Millisecond)
    	fmt.Println(" main over")
    }
    
    func numbers() {
    	for i := 1; i <= 5; i++ {
    		time.Sleep(250 * time.Millisecond)
    		fmt.Printf("%d", i)
    	}
    }
    
    func alphabets() {
    	for i := 'a'; i <= 'e'; i++ {
    		time.Sleep(400 * time.Millisecond)
    		fmt.Printf("%c", i)
    	}
    }
    

    运行结果

    1a23b4c5de main over
    

  • 相关阅读:
    马拉车算法【Manachar】
    AcWing算法进阶课 基础算法 启发式合并
    iframe嵌套跨域子页面变化高度自适应
    js数组中的每一项异步请求
    利用geo3d地图数据画地图上面的柱子
    地图上面加柱状图组
    antd-select选项位置偏移问题解决
    git
    React
    前端面试题
  • 原文地址:https://www.cnblogs.com/everydawn/p/13938817.html
Copyright © 2011-2022 走看看