首页 > 其他分享 >Go语言入门12(协程 goroutine)

Go语言入门12(协程 goroutine)

时间:2023-04-26 09:34:37浏览次数:41  
标签:wg 12 协程 函数 over goroutine 处理器

协程

进程和线程

进程

​ 当运行一个应用程序的时候,操作系统会为这个应用程序启动一个进程。可以将这个进程看作一个包含了应用程序在运行中需要用到和维护的各种资源的容器。这些资源包括但不限于内存地址空间、文件和设备的句柄以及线程

线程

​ 一个线程是一个执行空间,这个空间会被操作系统调度来运行函数中所写的代码。每个进程至少包含一个线程,每个进程的初始线程被称作主线程。因为执行这个线程的空间是应用程序的本身的空间,所以当主线程终止时,应用程序也会终止。操作系统将线程调度到某个处理器上运行,这个处理器并不一定是进程所在的处理器

并发和并行

并发

​ 并发是指在一个逻辑处理器同时管理很多事情,这些事情可能只做了一半就被暂停去做别的事情了,golang的并发通过切换多个线程打到减少物理处理器空闲等待的目的

并行

​ 并行是让不同的代码片段同时在不同的物理处理器上执行,大多数情况下,并发的效果比并行好,因为操作系统的硬件的总资源一般很少,但能支持系统同时做很多事情

goroutine协程

在一个协程中运行函数

​ 在一个协程中运行一个函数其实很简单,只要在函数调用前加上go即可

// 随便写一个demo函数
func Demo01(num int, contain string) {
	for i := 0; i < num; i++ {
		fmt.Println("这是一个goroutine", contain)
	}
}
// 在协程中运行此函数
func main() {
    go Demo01(10,"调用Demo函数")
	fmt.Println("over!")
}
//输出:
//   over!

​ 上述代码由于demo调用在协程中进行,所以并不影响主函数的运行,当主函数运行结束之后,代码运行直接停止,所以协程并没有输出任何内容,因此我们可以使用sleep方法让主函数进入等待状态

// 随便写一个demo函数
func Demo01(num int, contain string) {
	for i := 0; i < num; i++ {
		fmt.Println("这是一个goroutine", contain)
	}
}
// 在协程中运行此函数
func main() {
    go Demo01(10,"调用Demo函数")
    time.Sleep(1000000000)
	fmt.Println("over!")
}
//输出:
//   这是一个goroutine demo调用
//   这是一个goroutine demo调用
//   这是一个goroutine demo调用
//   这是一个goroutine demo调用
//   这是一个goroutine demo调用
//   over!

​ 但是这样子让主函数等待协程运行,听起来是个蛮蠢的想法,我们可以使用一个另一种方式解决问题,Waitgroup方法

waitgroup方法

​ 我们可以在使用waitgroup方法先实例化一个计数器,wg,在协程中使用wg.done进行操作计数器,从而达到主函数等待协程运行的一个目的

// demo方法
// 同时因为我们要对wg进行操作,因此要把wg的指针传递给函数
func Demo01(num int, contain string, wg *sync.WaitGroup) {
    // 因为wg,done一般来说都在函数最后使用,因此我们把他放在defer延迟处理函数里面
	defer wg.Done()
	for i := 0; i < num; i++ {
		fmt.Println("这是一个goroutine", contain)
		time.Sleep(1000000000)
	}
}

// main方法
func main() {
    // 实例化计数器wg
	var wg sync.WaitGroup
    // 要运行两个goroutine函数
	wg.Add(2)
	go functions.Demo01(2, "the first goroutine!", &wg)
	go functions.Demo01(3, "the second goroutine!", &wg)
    // 等待两个goroutine运行完毕
	wg.Wait()
    // 执行完毕后再输出over!
	fmt.Println("over!")
}
// 输出:
// 这是一个goroutine the second goroutine!
// 这是一个goroutine the first goroutine!
// 这是一个goroutine the first goroutine!
// 这是一个goroutine the second goroutine!
// 这是一个goroutine the second goroutine!
// over!

并发执行

​ 前文说过,并发执行就是让协程运行在同一个逻辑处理器上,我们可以在主方法中使用runtime.GOMAXPROCS(1)强制控制在一个逻辑处理器中

// main方法
func main() {
    routine.GOMAXPROCS(1)
    // 实例化计数器wg
	var wg sync.WaitGroup
    // 要运行两个goroutine函数
	wg.Add(2)
	go functions.Demo01(2, "the first goroutine!", &wg)
	go functions.Demo01(3, "the second goroutine!", &wg)
    // 等待两个goroutine运行完毕
	wg.Wait()
    // 执行完毕后再输出over!
	fmt.Println("over!")
}

​ 这样子会让处理器在两个工作中不断的切换,而并不是真正的同时进行,而真正的同进行,需要并行执行

并行执行

​ 并行执行就是让各个goroutine都在单独的逻辑处理器中运行,这时runtime.GOMAXPROCS(tmp)中的tmp参数就应给等于你的goroutine个数,同时我们可以使用runtime.NumCPU()来返回自己电脑中的物理处理器个数,而物理处理器的个数是和自己电脑的处理器挂钩的

// main方法
func main() {
    routine.GOMAXPROCS(2)
    fmt.Println(runtime.NumCPU()) // 20
    // 实例化计数器wg
	var wg sync.WaitGroup
    // 要运行两个goroutine函数
	wg.Add(2)
	go functions.Demo01(2, "the first goroutine!", &wg)
	go functions.Demo01(3, "the second goroutine!", &wg)
    // 等待两个goroutine运行完毕
	wg.Wait()
    // 执行完毕后再输出over!
	fmt.Println("over!")
}

​ 通过并行执行,我们就可以保证不同的协程是同时运行在不同的逻辑处理器当中,可以实行同时运行

标签:wg,12,协程,函数,over,goroutine,处理器
From: https://www.cnblogs.com/te9uila/p/17354661.html

相关文章

  • 12.存钱问题
     问题分析:  代码:#include<stdio.h>voidmain(){ inti; doublemoney=0.0; for(i=0;i<5;i++) money=(money+1000.0)/(1+0.0063*12); printf("应存入的钱数为:%0.2f\n",money);}......
  • C++第四章课后习题4-12
    定义一个datatype类,能处理包含字符型,整形,浮点型3种类型的数据,给出其构造函数。1#include<iostream>2usingnamespacestd;34classDataType{5private:6chara;7intn;8floatx;9enum{10character,11intege......
  • 打卡12
    2.9设汉王的失算 这道题非常的简单,直接从2的0次方加到2的63次方即可#include<bits/stdc++.h>usingnamespacestd;intmain(){ doubleans=0; for(inti=0;i<64;i++) { ans+=pow(2,i); } cout<<ans<<endl;} 2.10马克思手稿中的数学题 设x为男人,y为女人,z为小孩则满足x......
  • 【IT老齐012】外键约束
    【IT老齐012】外键约束优点保证数据的完整性和一致性级联操作方便数据一致性交给数据库,代码量小缺点性能问题额外的数据一致性校验查询并发问题外键约束会启用行级锁主表写入时会进入阻塞级联删除问题多层级联删除会让数据变得不可控数据耦合问题数据库......
  • ASEMI代理ADI亚德诺ADG5412BRUZ-REEL7车规级芯片
    编辑-ZADG5412BRUZ-REEL7芯片参数:型号:ADG5412BRUZ-REEL7开态电阻:9.8Ω电源断开漏电流:±0.05nA输入高电压:2V输入低电压:0.8V输入电流:0.002μA数字输入电容:2.5pF−3dB带宽:167MHzVDDtoGND:−0.3Vto+48VVSStoGND:+0.3Vto−48V工作温度范围:−40°Cto+125°C......
  • P.10-准备工作、P.11-数据库校验用户准备工作、P.12-数据库验证用户核心代码实现
    P.10-准备工作1.添加依赖<!--redis依赖--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency>......
  • Moving to Nuremberg UVA12223
    题目大意:给出n,一个无根的树,每条边上都有权值。现在每个位置都有一个景点,一个人想在一年之内去cnt[i]次景点,所以接下来给出m,表示说在m个位置上有这个人想去的地方,给出位置以及想去的次数(注意,每去一个景点都要返回自己的住处),namo这个人该住在哪里走的路程才最短。换根dp#incl......
  • fiddler和F12的区别
    抓包工具抓包 抓的是协议,fiddler抓的是HTTP、HTTPS协议,                      wireshark抓的是其他协议1)F12只能对Web进行抓包,Fiddler既可以对Web应用进行抓包,也可以对客户端及App进行抓包;2)F12无法篡改请求数据,而Fiddler可以;fid......
  • 虚拟机热迁移一直处于迁移中的状态-v4-20210308_124243
    虚拟机热迁移一直处于迁移中的状态企业云平台产品中心共享知识库Exportedon03/08/2021TableofContents问题现象:对虚拟机进行热迁移操作,Dashboard和云服务自助平台上一直处于迁移中的状态问题原因:虚拟机存在频繁的数据读写操作,导致虚拟机迁移的速度追不上数据读写的速度,每次迁......
  • Virsh常用命令-v4-20210308_123613
    Virsh常用命令企业云平台产品中心共享知识库Exportedon03/08/2021TableofContentsVirsh是基于libvirt写的一个命令行工具,用来通过Virsh来对虚拟机的生命周期进行管理,以下是常用的一些Virsh命令:1、查看在运行的虚拟机virshlist2、查看创建的所有虚拟机virshlist--all3、启......