Go语言Goroutinue和管道效率详解
作者:山与路 发布时间:2024-02-02 18:19:09
goroutinue基本介绍
进程和线程说明
进程介绍程序在操作系统中的一次执行过程,是系统进行资源分配和调度的基本单位
线程只是进程的一个执行实例或流程,是程序执行的最小单元
一个进程可以有多个线程,但是一个线程只能对应一个进程
同一个进程中的多个线程可以并发执行
程序:运行起来的应用程序就称为进程,也就是当程序不运行的时候我们称为程序,当程序运行起来他就是一个进程,通俗的理解就是不运行的时候是程序,运行起来就是进程。程序只有一个,但是进程有多个
并发和并行
并发:多个任务依次执行,执行过程中多个任务可以替换执行,在某一个时刻是一个任务在执行,但是在某个时间段内是多个任务在执行。
并行:多个任务没有顺序,同时执行,最终的执行结果跟耗时最长的任务有关
串行:多个任务依次执行,上一个任务没有完成时不能执行后续的任务,最明显的同步执行过程
同步和异步
同步:描述的就是串行执行过程,多个任务按照顺序依次执行的过程
异步:描述的就是并发和并行的过程,就是多个任务在一个时间段内同时执行,每个任务都不会等待其他任务执行完成后执行
Go协程和Go主线程
Go主线程:一个Go线程上,可以起多个协程,协程是轻量级的线程
go协程特点
有独立的栈空间
共享程序堆空间
调度由用户控制
协程是轻量级的线程
goroutinue基本使用
实验代码
package main
import (
"fmt"
"runtime"
"strconv"
"time"
)
func main() {
//编写一个函数,每隔1s输出"hello,world"
//要求主线程和gorutine同时执行
go test()
//在主线程中,开启一个goroutine,该协程每隔1s输出"hello,world"
for i:=1;i<=10 ; i++ {
fmt.Println("main() hello world", strconv.Itoa(i))
time.Sleep(time.Second)
}
//查询Golang运行的cpu数
fmt.Println(runtime.NumCPU()) //4
//设置Golang运行的cpu数
//runtime.GOMAXPROCS(runtime.NumCPU()-1)//3
}
func test(){
for i:=1;i<=10 ; i++ {
fmt.Println("test() hello world",strconv.Itoa(i))
time.Sleep(time.Second)
}
}
效果图
执行流程图
goroutinue的调度模型
MPG
MPG运行状态1
MPG运行状态2
管道(channel)
不同协程之间如何通讯
全局变量加锁同步
channel
使用全局变量加锁同步改进程序
因为没有对全局变量加锁,因此会出现资源夺取问题,代码会出现错误,提示concurrent map writes
加入互斥锁
全局变量加锁同步缺陷
主线程在等待所有goroutine全部完成的时间很难确定
如果主线程休眠时间长了,会加长等待时间,如果等待时间短了,可能还有goroutine处于工作状态,这时也会随着主线程的结束而结束
不利于多个协程对全局变量的读写操作
管道基本介绍
管道本质介绍一个数据结构-队列
数据是先进先出
线程安全,无需加锁
管道有类型
管道基本使用 声明和定义
管道关闭和遍历
关闭
使用内置函数close可以关闭channel,关闭后,就不能写入数据,但可读
遍历
在使用for--range遍历时,如果channel没有关闭,则回出现deadlock错误
在使用for--range遍历时,如果channel已经关闭,则会正常遍历数据
代码
package main
import "fmt"
func main() {
//定义管道
var intChan chan int
intChan =make(chan int,3)
//写入数据
intChan<-10
intChan<-20
intChan<-30
//遍历
close(intChan) //关闭管道
for value := range intChan {
fmt.Printf("%d\t",value) //102030
}
}
管道注意事项
-`channel可以声明为只读,或者只写性质
使用select可以解决从管道取数据的阻塞问题
goroutine中使用recover,解决协程中出现panic,导致程序崩溃问题
综合案例
package main
import "fmt"
func main() {
numChan := make(chan int, 2000)
resChan := make(chan int, 2000)
exitChan := make(chan bool, 8)
go putNum(numChan) //存放数据
//开启八个协程
for i := 0; i < 8; i++ {
go add(numChan, resChan, exitChan)
}
go func() {
for i:=0;i<8 ;i++ {
<-exitChan
}
close(resChan)
}()
for i := 1; i <=2000 ; i++ {
fmt.Printf("resChan[%d]=%d\n", i, <-resChan)
}
}
func putNum(numChan chan int) {
for i := 1; i <= 2000; i++ {
numChan <- i
}
close(numChan)
}
func add(numChan chan int, resChan chan int, exitChan chan bool) {
for {
n,ok := <-numChan
if !ok{
break
}
res := 0
for i := 1; i <= n; i++ {
res += i
}
resChan <- res
}
exitChan<-true
}
来源:https://juejin.cn/post/7146113493295431716
猜你喜欢
- model.pyimport datetimefrom django.contrib.auth.models import Userfrom
- SQL Server如何通过SQL语句直接操作另一个SQL SERVER的数据1、 现在执行SQL语句的数据库服务器开启Ad Hoc Dis
- 函数初解function,是一种语法结构,将实现某一个功能的代码块(多行代码)封装到一个结构中实现代码的重复利用函数定义语法:关键点:fun
- 在互联网出现之前,“抄”很不方便,一是“源”少,而是发布渠道少;而在互联网出现之后,“抄”变得很简单,铺天盖地的“源”源源不断,发布渠道也数
- 1、如何统计序列中元素的出现频度实际案例:(1)某随机序列[12, 5, 6, 4, 6, 5, 5, 7, ...] 中找到出现次数最高的
- vue+el使用this.$confirm不能阻断代码往下执行在vue+element ui的前端框架中使用el的confirm弹窗,遇到一
- 分页程序sub show_page参数说明:total_records 总记录数everypage_records 每页显示条数
- 一、在settings.py中配置DATABASES = { 'default': { 'ENGINE&
- 你说的就是真正的计数器,它只在有新的用户进入网站时,计数器才会加1,忠实可靠。把下列代码放到的global.asa的sessio
- Mac安装python3环境首先我先给说明一下:我也是初次接触python,有一定的Java基础,对编程语法有一定基础,当然小菜在这里全当小
- 前言:大家都知道python项目中需要导入各种包(这里的包引鉴于java中的),官话来讲就是Module。而什么又是Module呢,通俗来讲
- 主要步骤:import shutilshutil.copyfile(old_image,new_image)完整:这里要做的是,将原图片复制
- 我在工作的时候,在测试环境下使用的数据库跟生产环境的数据库不一致,当我们的测试环境下的数据库完成测试准备更新到生产环境上的数据库时候,需要准
- 目标是拷贝微信的飞机大战,当然拷贝完以后大家就具备自己添加不同内容的能力了。首先是要拿到一些图片素材,熟悉使用图像处理软件和绘画的人可以自己
- 缓存是基于Application实现的CacheState类,建议实例化时用名Cache程序代码<% Class Cache
- import reimport urllib2import cookielibdef renren():
- b.php的代码 <?php //只能通过post方式访问 if ($_SERVER['REQUEST_METHOD'
- 在网上搜索了半天,最简单的办法是在新的数据库中创建和原名字一样的数据库,然后把.frm 文件拷贝进去就OK了。 可是,有些时候这样不行,查询
- 这篇文章主要介绍了Python加密模块的hashlib,hmac模块使用解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的
- Django配置文件settings简单说明,包含时区语言等打开创建好的django工程,查看settings.py文件BASE_DIR =