Golang gorutine(协程)+channel

goroutine(协程)

Go的进程和Go的协程

  • Go进程:
    • 一个Go进程上,可以启动多个协程
  • Go协程:
    • 有独立栈空间
    • 共享堆空间
    • 调度由用户定义
    • 协程是轻量级线程
  • Go协程对比其他语言并发实现的优势
    • Go协程是进程开启的,是轻量级的线程,对资源耗费小
    • 其他语言的并发一般是基于线程的
    • Go协程可以轻松开上万个,而其他语言开上万个并发较为吃力

Go协程的使用

// 编写一个程序,满足以下功能:
// 1. 在进程中,开启一个 goroutine,该协程每隔1秒输出 "hello world"
// 2. 在进程中,也每隔1秒输出 "hello golang",输出10次后,进程结束
// 3. 要求进程和 goroutine 同时执行

package main

import (
    "fmt"
    "time"
    "strconv"
)

func test() {
    for i := 0; i < 10; i++ {
        fmt.Println("[test] hello world" + strconv.Itoa(i))
        time.Sleep(time.Second)
    }
}

func main() {
    
    go test() // 开启一个协程,执行这个 test
    
    for i := 0; i < 10; i++ {
        fmt.Println("[main] hello golang" + strconv.Itoa(i))
        time.Sleep(time.Second)
    }
}

goroutine协程的调度模型

  • MPG模型
  • M:操作系统上的进程(主线程)
  • P:协程需要的上下文
  • G:协程

查看和设置Go运行的cpu数目

  • 概述

    • go1.8以后,默认让程序运行多个核,可以不设置
    • go1.8之前,最好进行设置,从而提高性能
  • 查看系统的逻辑cpu数目

    import "runtime"
    
    fmt.Println(runtime.NumCPU())
    
  • 设置执行Go程序的cpu个数

    import "runtime"
    
    runtime.GOMAXPROCS(num) // 本函数在编译优化时会被去掉
    
goroutine中使用 recover
  • goroutine中使用 recover,可以解决某个协程中出现 panic,导致整个程序崩溃的问题

    defer func() {
        if err := recover(); err != nil {
            fmt.Println("发生错误", err)
        }
    }
    

channel

goroutine资源竞争的问题

// 下面程序会发成 资源竞争问题(concurrent map writes)
// 查看是否发生资源竞争问题可以用命令:go build -race test.go
// 现采用goroutine计算1-200各个数的阶乘,并把每个数的阶乘放进map中,最后显示出来

package main

import (
    "fmt"
    "time"
)

var (
    myMap = make(map[int]int, 10)
)

func calculate(n int) {
    
    res := 1
    for i := 1; i <= n; i++ {
        res *= i
    }
    
    myMap[n] = res
}

func main() {
    for i := 1; i <= 200; i++ {
        go test(i)
    }
    
    time.Sleep(20 * time.Second) // 避免goroutine还没执行,主线程就结束了
    
    for k,v := range myMap {
        fmt.Printf("map[%d]%d\n", k, v)
    }
}

解决资源竞争问题 - 通过全局变量加锁

package main

import (
    "fmt"
    "time"
    "sync"
)

var (
    myMap = make(map[int]int, 10)
    lock sync.Mutex // 全局的互斥锁
)

func calculate(n int) {
    
    res := 1
    for i := 1; i <= n; i++ {
        res *= i
    }
    
    lock.Lock()    // 加锁
    myMap[n] = res
    lock.Unlock()  // 解锁
}

func main() {
    for i := 1; i <= 200; i++ {
        go calculate(i)
    }
    
    time.Sleep(20 * time.Second) // 避免goroutine还没执行,主线程就结束了
    
    lock.Lock()    // 加锁
    for k,v := range myMap {
        fmt.Printf("map[%d]%d\n", k, v)
    }
    lock.Unlock()  // 解锁
}

解决资源竞争问题 - 通过channel

全局变量锁的缺点
  • 主线程等待所有 goroutine 全部完成的时间很难确定
  • 通过全局变量锁实现的同步,不利于多个协程对全局变量的读写操作
channel 介绍
  • channel 是一个引用类型
  • channel的本质是一个队列
  • 数据是先入先出的,即多个 goroutine 同时访问时,也不需要加锁
  • channel是有类型的,一个string类型的channel只能存放string
channel 声明
var 变量名 chan 数据类型

var intChan chan int
var mapChan chan map[int]string
var perChan chan Person
channel 初始化
  • channel 必须初始化后才能使用,即 make 后
var intChan chan int = make(chan int, 3)
channel 写入数据
intChan <- 10

// channel数据放满后就不能再放了,容量不是动态增长的
channel读取数据
var num int
num = <- intChan

// 在没有使用协程的情况下,当channel已经为空,但是依然继续取时,会报 deadlock
channel长度和容量
len(intChan)
cap(intChan)
channel关闭
// 关闭 channel 后,就不能再往里面写数据了,但如果 channel 里面还有数据,则可以继续读取
close(intChan)
channel遍历
// 在遍历时,如果 channel 还没关闭,则会报 deadlock
// 在遍历时,如果 channel 已经关闭,则遍历正常执行

for v := range intChan {
    fmt.Println("v=", v)
}
channel阻塞机制
如果只向 channel 中写入数据而不读取,导致 channel 满了,还继续写,就会出现阻塞而 deadlock

如果读的频率远低于写的频率也没有问题,也不会发生 deadlock,关键是要去读
channel 只读与只写
var chan1 chan int // 可读可写
var chan2 chan <- int // 只写
var chan3 <- chan int // 只读
channel与select
// 使用 select 可以解决从管道取数据阻塞的问题

// 1. 定义一个管道 10个数据int
intChan := make(chan int, 10)
for i := 0; i < 10; i++ {
    intChan <- i
}
// 2. 定义一个管道  5个数据string
strChan := make(chan string, 5)
for i := 0; i < 10; i++ {
    intChan <- "hello" + fmt.Sprintf("%d", i)
}

// 在 for-range 遍历管道时,如果不关闭管道,会发生 deadlock 现象
// 但是我们可能不好确定什么时候该关闭管道
// 可以使用 select 方法解决
for {
    select {
        // 这里,如果管道没有关闭,也不会因为一直阻塞而 deadlock
        // 会自动到下一个 case 匹配
        case v := <- intChan:
            fmt.Println("从 intChan 读取数据%v\n", v)
        case v :=  <- strChan:
            fmt.Println("从 strChan 读取数据%v\n", v)
    	default:
        	fmt.Println("都没取到")
    }
}

通过 channel 解决素数问题

代码实现
package main
import (
    "fmt"
)

func putNum(intChan chan int) {
    
    for i := 0; i < 1000; i++ {
        intChan <- i
    }
    
    close(intChan)
}

func primeNum(intChan chan int, primeChan chan int, exitChan chan bool) {
    var flag bool
    for {
        num, ok := <- intChan
        
        if !ok {
            break
        }
        
        flag = true
        for i := 2; i < num; i++ {
            if num % i == 0 {
                flag = false
                break
            }
        }
        
        if flag {
            primeChan <- num
        }
    }
    
    fmt.Println("有一个primeChan因为取不到数了而退出")
    exitChan <- true
}

func main() {
    
    intChan := make(chan int, 1000)
    primeChan := make(chan int, 1000)
    exitChan := make(chan bool, 4)
    
    go putNum(intChan)
    
    for i := 0; i < 4; i++ {
        go primeNum(intChan, primeChan, exitChan)
    }
    
    go func() {
        for i := 0; i < 4; i++ {
            <- exitChan
        }

        close(primeNum)
    }()
    
    for {
        res, ok := <- primeNum
        if !ok {
            break
        }
        fmt.Printf("素数:%d\n", res)
    }
    
    fmt.Println("main线程退出")
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/782508.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

vscode调试教程

VSCode调试 VSCode Debuggers VSCode使用launch.json进行细粒度的控制&#xff0c;可以启动程序或将其附加到复杂的调试场景中 打开Run and Debug视图Ctrl Shift D 点击create a launch.json file&#xff0c;选择C(GDB/LLDB) 会在工作目录自动创建.vscode/launch.json文…

简单的基追踪一维信号降噪方法(MATLAB 2018)

基追踪法是基于冗余过完备字典下的一种信号稀疏表示方法。该方法具有可提高信号的稀疏性、实现阈值降噪和提高时频分辨率等优点。基追踪法采用表示系数的范数作为信号来度量稀疏性&#xff0c;通过最小化l型范数将信号稀疏表示问题定义为一类有约束的极值问题&#xff0c;进而转…

【linux服务器】大语言模型实战教程:LLMS大模型部署到个人服务器或嵌入式开发板(保姆级教学)

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏: 《C干货基地》《粉丝福利》 ⛺️生活的理想&#xff0c;就是为了理想的生活! 引言 说到大语言模型相信大家都不会陌生&#xff0c;大型语言模型(LLMs)是人工智能文本处理的主要类型,也现在最流行的人工智能…

julia系列17: tsp问题代码整理

1. 常用库和基础函数 这里是优化版的函数&#xff1a; using TSPLIB,LKH,Distances,PyPlot MaxNum 10000 tspreadTSPLIB(:att48) dist [round.(Int,euclidean(tsp.nodes[i,:],tsp.nodes[j,:])) for i in 1:tsp.dimension,j in 1:tsp.dimension]; pos(tsp::TSP,t::Vector{In…

Games101学习笔记 Lecture17 Materials and Appearances

Lecture17 Materials and Appearances 材质 BRDF一、Diffuse/Lambertian Material二、Glossy Material三、Ideal reflective/ refractive Material (BSDF)1.镜面反射2.镜面折射3.菲涅尔项 Fresnel 四、Microfacet BRDF 微表面五、Isotropic / Anisotropic Materials (BRDFs)An…

python - 文件 / 永久存储:pickle / 异常处理

一.文件 利用help(open)可以看到open()函数的定义&#xff1a; >>> help(open) Help on built-in function open in module _io:open(file, moder, buffering-1, encodingNone, errorsNone, newlineNone, closefdTrue, openerNone) 默认打开模式是’rt’&#xff0…

王者荣耀与和平精英的语音识别不准确怎么办?分享一次意想不到的解决经历!

文章目录 📖 介绍 📖🏡 演示环境 🏡📒 完整经历 📒🔍 问题初现 🔍🔎 排查之路:从绝望到希望的转折 🔎🎉 顿悟时刻:原来是“她”的恶作剧 🎉⚓️ 相关链接 ⚓️📖 介绍 📖 作为一位打字速度惊人的玩家,我向来自豪于能在王者荣耀和和平精英等游戏…

Three.js机器人与星系动态场景(四):封装Threejs业务组件

实际在写业务的时候不会在每个组件里都写几十行的threejs的初始化工作。我们可以 将通用的threejs的场景、相机、render、轨道控制器等进行统一初始化。同时将非主体的函数提到组件外部&#xff0c;通过import导入进组件。将业务逻辑主体更清晰一些。下面的代码是基于reactthre…

DHCP与TCP的简单解析

目录 一、DHCP 1.1 DHCP概述 1.2 DHCP的优势 1.3 DHCP的模式与分配方式***** 1.3.1 DHCP的模式&#xff1a;C/S模式&#xff08;客户机与服务器模式&#xff09; 1.3.2 DHCP的分配方式 1.4 DHCP的租约过程及原理 1.4.1 DHCP的工作原理***** 1.4.2 更新租约原理***** …

智慧校园-基础平台功能总体概述

智慧校园基础平台是现代教育信息化的核心&#xff0c;它集成了系统管理、基础数据、系统监控、系统工具、流程管理等关键功能&#xff0c;构建了一个全面、智能、安全的校园生态系统。系统管理部分&#xff0c;通过权限管理和用户管理&#xff0c;实现了对用户访问权限的精细化…

使用qt creator配置msvc环境(不需要安装shit一样的宇宙第一IDE vs的哈)

1. 背景 习惯使用Qt编程的童鞋&#xff0c;尤其是linux下开发Qt的童鞋一般都是使用qt creator作为首选IDE的&#xff0c;通常在windows上使用Qt用qt creator作为IDE的话一般编译器有mingw和msvc两种&#xff0c;使用mingw版本和在linux下的方式基本上一样十分简单&#xff0c;不…

warning: GOPATH set to GOROOT (D:\go) has no effect

warning: GOPATH set to GOROOT (D:\go) has no effect gopath 设置一下&#xff0c;并且不要和 goroot 设置成同一个目录

【carla】ubuntu安装carla环境

我们可以通过查看 CARLA 的 GitHub release 页面来找到最新版本的下载链接。 下载 CARLA 压缩包 访问 CARLA Releases 页面&#xff1a; CARLA Releases on GitHub 查找最新版本&#xff1a; 找到最新的版本&#xff0c;点击下载&#xff0c;第一个压缩包 3. 解压 CARLA 包&…

在先企业字号被申请注册成商标!

今天一网友联系普推商标知产老杨&#xff0c;说自己注册的商标被某公司无效宣告了&#xff0c;去年联系老杨时&#xff0c;当时就给说这个商标名称存在风险&#xff0c;与别人的字号权存在高度近似&#xff0c;而且是同行业同地区在后面注册的。 十几年前某公司先成功注册成字号…

AI Agent【项目实战】:MetaGPT遇上元编程,重塑复杂多智能体协作的边界

AI Agent【项目实战】&#xff1a;MetaGPT遇上元编程&#xff0c;重塑复杂多智能体协作的边界 MetaGPT 以一条需求作为输入&#xff0c;并输出用户故事/竞争分析/需求/数据结构/API/文档等。内部而言&#xff0c;MetaGPT 包含产品经理/架构师/项目经理/工程师等角色。它为软件…

树目标、抓过程、要结果

一个好的管理理念不会因为一两个成功案例而发扬&#xff0c;一定是有无数个案例验证了它的价值所在&#xff0c;既然OKR在国外已经取得成功&#xff0c;那么国内依然如此。那么OKR这么成功&#xff0c;它到底好在哪呢&#xff1f; 一、OKR是连接企业战略和落地执行的最佳方式。…

ftp服务

1.什么是FTP FTP&#xff08;文件传输协议&#xff09;是典型的C/S架构的应用层协议&#xff0c;需要由服务端软件、客户端软件两个部分共同实现文件传输功能。FTP客户端和服务器之间的连接是可靠的&#xff0c;面向连接的&#xff0c;为数据的传输提供了可靠的保证。tcp协议&a…

1.2 如何让机器说人话?万字长文回顾自然语言处理(NLP)的前世今生 —— 《带你自学大语言模型》系列

本系列目录 《带你自学大语言模型》系列部分目录及计划&#xff0c;完整版目录见&#xff1a;带你自学大语言模型系列 —— 前言 第一部分 走进大语言模型&#xff08;科普向&#xff09; 第一章 走进大语言模型 1.1 从图灵机到GPT&#xff0c;人工智能经历了什么&#xff1…

【3GPP核心网】【5G】精讲5G核心网系统架构主要特征

目录 前言 1. 5G核心网系统架构主要特征 1.1 5G核心网与4G核心网EPC区别 1.2 5G核心网系统架构主要特征 2. 5G网络逻辑架构 2.1 新型基础设施平台 2.2 逻辑架构 前言 首先需要理解核心网的角色定位&#xff0c;作为移动通信网络的核心部分&#xff0c;核心网起着承上启下的作用…

阶段三:项目开发---大数据开发运行环境搭建:任务3:安装配置Hadoop集群

任务描述 知识点&#xff1a;安装配置Hadoop 重 点&#xff1a; 安装配置Hadoop 难 点&#xff1a;无 内 容&#xff1a; Hadoop是一个由Apache基金会所开发的分布式系统基础架构。用户可以在不了解分布式底层细节的情况下&#xff0c;开发分布式程序。充分利用集群的威…