goroutine是什么

goroutine即协程,使用go关键字开启一个协程异步执行代码。

注意,main函数也是个goroutine。

基本使用

使用go执行子任务,会交替执行(和时间片一样)。

主goroutine退出后,其它的工作goroutine也会自动退出(有点父子进程的感觉):

package main

import (
"fmt"
"time"
) func newTask() {
i := 0
for {
i++
fmt.Printf("new goroutine: i = %d\n", i)
time.Sleep(1 * time.Second) //延时1s
}
} func main() {
//创建一个 goroutine,启动另外一个任务
go newTask() i := 0
//main goroutine 循环打印
for {
i++
fmt.Printf("main goroutine: i = %d\n", i)
time.Sleep(1 * time.Second) //延时1s
}
//这里是加入了死循环,如果去掉,则程序会直接退出。
}

多个协程的顺序是不一定的。

var _ = runtime.GOMAXPROCS(3)
var a, b int
func u1() {
a = 1
b = 2
}
func u2() {
a = 3
b = 4
}
func p() {
println(a)
println(b)
}
func main() {
go u1() // 多个 goroutine 的执行顺序不定
go u2()
go p()
time.Sleep(1 * time.Second)
}

runtime包

Gosched

runtime.Gosched() //让别人先执行,需要同时需要时间片的时候才会有效,对方如果已经停了就还是自己执行。

就像孔融让梨(梨就是CPU时间片),A遇到runtime.Gosched()就先给B吃(让出时间片),但是如果B已经吃完了(B已经不需要时间片了),A就开始吃(A则开始占用CPU)。

func main() {
//创建一个goroutine
go func(s string) {
for i := 0; i < 2; i++ {
fmt.Println(s)
}
}("world") for i := 0; i < 2; i++ {
runtime.Gosched() //import "runtime"
/*
屏蔽runtime.Gosched()运行结果如下:
hello
hello 没有runtime.Gosched()运行结果如下:
world
world
hello
hello
*/
fmt.Println("hello")
}
}

优先调度:

你的程序可能出现一个 goroutine 在运行时阻止了其他 goroutine 的运行,比如程序中有一个不让调度器运行的 for 循环:

调度器会在 GC、Go 声明、阻塞 channel、阻塞系统调用和锁操作后再执行,也会在非内联函数调用时执行:

func main() {
done := false
go func() {
done = true
}()
//这里占用了调度,协程无法启动
for !done {
println("not done !") // 并不内联执行
}
println("done !")
} //可以添加 -m 参数来分析 for 代码块中调用的内联函数 修改: func main() {
done := false
go func() {
done = true
}()
for !done {
runtime.Gosched()
}
println("done !")
}

Goexit

runtime.Goexit() //将立即终止当前 goroutine 执⾏,调度器确保所有已注册 defer延迟调用被执行。

package main

import (
"fmt"
"runtime"
"time"
) //调用 runtime.Goexit() 将立即终止当前 goroutine 执⾏,调度器确保所有已注册 defer延迟调用被执行。 func main() {
go func() {
defer fmt.Println("A.defer") func() {
defer fmt.Println("B.defer")
runtime.Goexit() // 终止当前 goroutine, import "runtime"
fmt.Println("B") // 不会执行
}() defer fmt.Println("C.defer") //还没来得及注册,不会执行 fmt.Println("A") // 不会执行
}() //别忘了() //死循环,目的不让主goroutine结束
for {
time.Sleep(1 * time.Second)
}
} //执行结果:
//B.defer
//A.defer

GOMAXPROCS

调用 runtime.GOMAXPROCS() 用来设置可以并行计算的CPU核数的最大值,并返回之前的值。

示例代码:

func main() {
//n := runtime.GOMAXPROCS(1)
//打印结果:111111111111111111110000000000000000000011111...
n := runtime.GOMAXPROCS(2)
//打印结果:010101010101010101011001100101011010010100110...
fmt.Printf("n = %d\n", n) for {
go fmt.Print(0)
fmt.Print(1)
}
}

在第一次执行(runtime.GOMAXPROCS(1))时,最多同时只能有一个goroutine被执行。所以会打印很多1。

过了一段时间后,GO调度器会将其置为休眠,并唤醒另一个goroutine,这时候就开始打印很多0了,在打印的时候,goroutine是被调度到操作系统线程上的。

在第二次执行(runtime.GOMAXPROCS(2))时,我们使用了两个CPU,所以两个goroutine可以一起被执行,以同样的频率交替打印0和1。

【Go并发编程】Goroutine的基本使用的更多相关文章

  1. golang并发编程goroutine+channel(一)

    go语言的设计初衷除了在不影响程序性能的情况下减少复杂度,另一个目的是在当今互联网大量运算下,如何让程序的并发性能和代码可读性达到极致.go语言的并发关键词 "go" go dos ...

  2. Golang并发编程——goroutine、channel、sync

    并发与并行 并发和并行是有区别的,并发不等于并行. 并发 两个或多个事件在同一时间不同时间间隔发生.对应在Go中,就是指多个 goroutine 在单个CPU上的交替运行. 并行 两个或者多个事件在同 ...

  3. go语言并发编程

    引言 说到go语言最厉害的是什么就不得不提到并发,并发是什么?,与并发相关的并行又是什么? 并发:同一时间段内执行多个任务 并行:同一时刻执行多个任务 进程.线程与协程 进程: 进程是具有一定独立功能 ...

  4. Golang并发编程优势与核心goroutine及注意细节

    Go语言为并发编程而内置的上层API基于CSP(communication sequential processes,顺序通信进程)模型.这就意味着显式锁都是可以避免的,比如资源竞争,比如多个进程同时 ...

  5. Go中的并发编程和goroutine

    并发编程对于任何语言来说都不是一件简单的事情.Go在设计之初主打高并发,为使用者提供了goroutine,使用的方式虽然简单,但是用好却不是那么容易,我们一起来学习Go中的并发编程. 1. 并行和并发 ...

  6. Go part 8 并发编程,goroutine, channel

    并发 并发是指的多任务,并发编程含义比较广泛,包含多线程.多进程及分布式程序,这里记录的并发是属于多线程编程 Go 从语言层面上支持了并发的特性,通过 goroutine 来完成,goroutine ...

  7. 【Go入门教程7】并发(goroutine,channels,Buffered Channels,Range和Close,Select,超时,runtime goroutine)

    有人把Go比作21世纪的C语言,第一是因为Go语言设计简单,第二,21世纪最重要的就是并行程序设计,而Go从语言层面就支持了并行. goroutine goroutine是Go并行设计的核心.goro ...

  8. golang并发编程

    golang并发编程 引子 golang提供了goroutine快速实现并发编程,在实际环境中,如果goroutine中的代码要消耗大量资源时(CPU.内存.带宽等),我们就需要对程序限速,以防止go ...

  9. Go并发编程实践

    前言 并发编程一直是Golang区别与其他语言的很大优势,也是实际工作场景中经常遇到的.近日笔者在组内分享了我们常见的并发场景,及代码示例,以期望大家能在遇到相同场景下,能快速的想到解决方案,或者是拿 ...

  10. Go语言 并发编程

    Go语言 并发编程 作者:Eric 微信:loveoracle11g 1.创建goroutine // 并行 是两个队列同时使用两台咖啡机 // 并发 是两个队列交替使用一台咖啡机 package m ...

随机推荐

  1. vscode配置remote ssh

    前言 简单用vscode配置 remote ssh可以实现,通过ssh 在线使用vscode编辑文件,很方便,也遇到一些坑. 安装插件 设置界面 右键最左边tab栏: 勾选 远程资源管理器 添加远程服 ...

  2. 第2-4-7章 docker安装WorkBench-规则引擎Drools-业务规则管理系统-组件化-中台

    目录 8. WorkBench 8.1 WorkBench简介 8.2 安装方式 8.2.1 传统方式安装 8.2.2 docker安装drools workbench 8.3 使用方式 8.3.1 ...

  3. oracle 内置函数(二)字符函数

    主要函数: 大小写转换函数 获取子字符串函数(字符串截取) 获取字符串长度函数 字符串连接函数 去除子字符串函数 字符替换函数 字符串出现次数 字符串按照特定符号拆分多行 一.大小写转换 1.uppe ...

  4. 【SQL】DML语句-SQL更新与删除:单表更新删除与连表更新删除语法

    〇.概述 1.资料 sql连表删除:http://www.lanxinbase.com/?tag=sql%E8%BF%9E%E8%A1%A8%E5%88%A0%E9%99%A4 sql实现两表关联更新 ...

  5. java中的字符串数组

    本文主要讲述java中的字符串数组 字符串数组的声明有如下几种形式: // 第一种方式:new // 注意在String的后面[]中不需要添加字符串数组的长度.否则报错. String[] arr_1 ...

  6. Spring IOC官方文档学习笔记(二)之Bean概述

    1.Bean概述 (1) Spring IoC容器管理一个或多个bean,这些bean是根据我们所提供的配置元数据来创建的,在容器内部,BeanDefinition对象就代表了bean的配置元数据,它 ...

  7. JavaScript:对象:如何创建对象?

    JS是面向对象的语言,除开基础数据类型,其他所有的数据类型都是对象,包括函数. 如何去理解对象,什么是对象呢? 举个例子,比如我们将日常生活中见到的猫这种动物,抽象成一个类Cat,这里不去谈类是什么概 ...

  8. 15、MySQLTransactionRollbackException: Lock wait timeout exceeded; try restarting transaction

    转载自 一.报错信息: Error updating database. Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollback ...

  9. Python实验报告(第13章)

    实验13:Pygame游戏编程 一.实验目的和要求 学会Pygame的基本应用 二.Pygame的优点及应用 使用Python进行游戏开发的首选模块就是Pygame,专为电子游戏设计(包括图像.声音) ...

  10. UOJ33 [UR#2] 树上 GCD

    UOJ33 [UR#2] 树上 GCD 简要题意: 给定一棵有根树,对于每个 \(i \in [1,n)\),求出下式的值: \[Ans[i] = \sum_{u<v} \gcd({\rm{di ...