并发编程【深度解剖】

简介: 本篇文章更多用诙谐的语调讲解,易于理解。

并发介绍

谈到并发,随之而来的就是那几个问题。并发 并行 线程 进程
注意!!!本篇文章更多用诙谐的语调讲解,为保证易于理解,不够官方正式,所以可以结合AI读本篇文章,并且本文是以 go语言 的角度来看问题的。(~ ̄▽ ̄)~,祝大家收获满满。

进程与线程

1、进程是程序在操作系统进行的一次操作过程
2、线程是进程的一个执行实体(线程就相当于进程派出的小兵,可以独立执行任务)
3、一个进程可以创建和撤销多个线程(可以同时派出多个小兵、也可以同时让士兵们撤退)

并发与并行

`并发` 相当于一群人喝一瓶饮料,但是只有一根吸管,于是乎大家轮流喝。
`并行` 相当于一群人喝一瓶饮料,但是大家富有了,于是又买了几根吸管,
这时大家可以一起喝。

并发:
在这里插入图片描述
并行:
在这里插入图片描述

线程与协程

1、线程与协程之间的关系,类似线程与协程之间的关系,在一个线程上可以跑多个协程。
2、由一个线程发起的协程,就像一个连队,共享一个堆空间(共享信息、如类、对象...等等),
而每个线程又有独立的栈空间。

Goroutine特性

通信共享内存!
初次听到这个,你可能有点疑惑,啥是通信共享内存?
这里的 “内存” ,并不是大家明面意思上理解的,对同一片内存区域进行操作。
你可以简答的理解为旋转小火锅内的一盘菜,大家轮流拿着下火锅(通过channel实现)。
如果盘子里没菜了,那说明菜被吃完了,信息自然也就无法共享了。

这里对标的是,Java、C++等一系列语言的“内存共享通信”,
他们才是对同一片内存区域进行操作,故需要进行繁琐的加锁去锁。

简单应用

只需要 go + 要调用的函数 即可(如下)。

func hello() {
   
    fmt.Println("Hello Goroutine!")
}
func main() {
   
    go hello() // go + 要调用的函数
    fmt.Println("main goroutine done!")
}

Goroutine调度

GPM是Go语言运行时(runtime)层面的实现,是go语言自己实现的一套调度系统。
区别于操作系统调度OS线程。
接下来详细解释一下GPM中,分别对应什么:
G:对应着一个goroutine协程,内部存着本goroutine的信息,以及与其绑定P的信息
P:P管理着一组goroutine队列,P里面会存储当前goroutine运行的上下文环境。
M:是Go运行时(runtime)对操作系统内核线程的虚拟。与内核线程一一映射。

接下来,这个这张图片可以更好的描述
在这里插入图片描述

优势

看到这里,相信大家已经看到go语言实现并发的优点
其他语言要实现这一点,需要手搓一个线程池(进程、线程),但是go真正实现了通过一个gorountine走天下。
在这里插入图片描述

runtime包

runtime包在并发领域,具有代表性的三个函数。
在这里插入图片描述

runtime.Gosched(),让出CPU时间片,重新等待安排任务
runtime.Goexit(),退出当前协程
runtime.GOMAXPROCS,Go运行时的调度器使用GOMAXPROCS参数
来确定需要使用多少个OS线程来同时执行Go代码

当只设置一个核心的时候,并配合让权等待,就能完美实现,交替打印。

package main

import (
    "fmt"
    "runtime"
    "time"
)

func a() {
   
    for i := 1; i < 10; i++ {
   
        fmt.Println("A:", i)
        runtime.Gosched()
    }
}

func b() {
   
    for i := 1; i < 10; i++ {
   
        fmt.Println("B:", i)
        runtime.Gosched()
    }
}

func main() {
   
    runtime.GOMAXPROCS(1)
    go a()
    go b()
    time.Sleep(time.Second)
}
记忆犹新,记得当时我调代码遇到一个问题->我把runtime.Goexit()放在main函数中
结果报了一个死锁的问题。
What???main函数死锁干嘛?他又不是协程???就算是协程,也不因该死锁呀???
我记得当时学操作系统时,死锁的四大条件分别是:
1、互斥条件
2、请求和保持条件
3、不可剥夺条件
4、循环等待条件
可是这些都跟main函数中放runtime.Goexit()没关系呀?

在 Go 里,程序要结束,main 函数所在的 Goroutine 得正常返回。要是在 main 函数中调用 runtime.Goexit(),main 函数就不会正常返回,这会让 Go 运行时觉得程序还在运行
要是除 main 函数的 Goroutine 之外没有其他活跃的 Goroutine 了,Go 运行时就会判定出现了死锁。这是因为程序既无法继续执行(无活跃的 Goroutine),又不能正常结束(main 函数未正常返回)。(正常的死锁就是这个条件)

扩展

深入了解runtime包,会发现其在go语言运行时,起着至关重要的作用
大家可以先尝试理解一下,下方这串文本

_rt0_amd64_linux (汇编入口)
  -> runtime.rt0_go (Go 入口)
      -> runtime.args (解析参数)
      -> runtime.osinit (初始化 OS 信息)
      -> runtime.schedinit (初始化调度器)
          -> 初始化堆、GC、P 等
      -> 创建主 Goroutine
          -> runtime.main()
              -> 执行所有 init()
              -> main.main()
  -> runtime.mstart (启动调度循环)

其实我想放出这段文本的根本原因,是因为我发现了一个好玩的东西。
go语言,执行程序的方式,很有趣。

在这里插入图片描述

Channel

单纯执行函数之间的并发是没有意思的。
重点!单纯的函数之间的并发是没有意思的!!!
函数与函数间需要交换数据才能体现并发执行函数的意义
所以这里会用到channel,也就是管道。
具体关于管道的知识,等咱在抽空写一篇。


借鉴博客:
1、深入浅出 Go 语言的 GPM 模型(Go1.21)


目录
相关文章
|
29天前
|
人工智能 机器人 API
OpenClaw阿里云无影云电脑一键部署实战:快速搭建、飞书无缝集成与常见问题解答
OpenClaw(原Clawdbot)作为轻量化、可扩展的AI智能体框架,凭借灵活的模型接入、多渠道消息分发与自动化任务能力,成为个人与团队搭建专属AI助手的优选。2026年,阿里云无影云电脑提供OpenClaw官方预置镜像,无需手动配置复杂环境,新手可通过桌面化操作快速完成云端部署。将OpenClaw接入飞书,可让AI助手直接在企业协作、团队沟通场景中响应指令、处理任务,实现从云端部署到实际应用的闭环。
578 11
|
1月前
|
存储 人工智能 关系型数据库
OpenClaw怎么可能没痛点?用RDS插件来释放OpenClaw全部潜力
OpenClaw插件是深度介入Agent生命周期的扩展机制,提供24个钩子,支持自动注入知识、持久化记忆等被动式干预。相比Skill/Tool,插件可主动在关键节点(如对话开始/结束)执行逻辑,适用于RAG增强、云化记忆等高级场景。
944 56
OpenClaw怎么可能没痛点?用RDS插件来释放OpenClaw全部潜力
|
1月前
|
前端开发 JavaScript 应用服务中间件
手把手教你给项目配 HTTPS(Nginx 实战教程,前端 + 后端)
本文章中你既能收获"为什么",也会收获"怎么做"。
368 5
手把手教你给项目配 HTTPS(Nginx 实战教程,前端 + 后端)
|
1月前
|
网络安全 Go Docker
CI/CD全流程
记录 后端go 算法平台 / python 爬虫网关 / 前端vue项目 CI-CD部署流程
280 8
|
1月前
|
机器学习/深度学习 存储 测试技术
DFS/BFS专练-搞定图论基础!(从海岛问题过渡至图论基础应用C/C++)
从海岛问题到图论基础:7 大经典场景 + N 个实战案例,彻底吃透 DFS/BFS 核心逻辑! 遇事不决,直接上纸,画图。
167 3
|
1月前
|
算法 机器人 测试技术
动态规划入门详解
等待了好久好久,今天终于可以对动态规划动手了(☆▽☆)
169 3
|
1月前
|
SQL Go
Go反射指南
反射与接口息息相关
131 2
|
1月前
|
Arthas 人工智能 Java
我们做了比你更懂 Java 的 AI-Agent -- Arthas Agent
Arthas Agent 是基于阿里开源Java诊断工具Arthas的AI智能助手,支持自然语言提问,自动匹配排障技能、生成安全可控命令、循证推进并输出结构化报告,大幅降低线上问题定位门槛。
1175 64
我们做了比你更懂 Java 的 AI-Agent -- Arthas Agent
|
19天前
|
Ubuntu 算法 关系型数据库
Debian/Ubuntu 环境 PolarDB-X 单机版 DEB 包安装综合指南
本文整合阿里云文档,详解Ubuntu 18.04与Debian 10下PolarDB-X单机版安装:因官方仅提供RPM包,需用alien转DEB,但二者压缩格式不同(Ubuntu用zstd,Debian 10不支持),必须在目标系统本地转换,不可复用。含依赖处理、配置初始化及启动验证全流程。
342 19