建立网站 英语,wordpress音乐播放插件,建一个信息 类网站,网站查询访问Golang 并发机制及 CSP 并发模型
Golang 是一门为并发而生的语言#xff0c;其并发机制基于 CSP#xff08;Communicating Sequential Processes#xff0c;通信顺序过程#xff09; 模型。CSP 是一种描述并发系统中交互模式的正式语言#xff0c;强调通过通信来共享内存…Golang 并发机制及 CSP 并发模型
Golang 是一门为并发而生的语言其并发机制基于 CSPCommunicating Sequential Processes通信顺序过程 模型。CSP 是一种描述并发系统中交互模式的正式语言强调通过通信来共享内存而不是通过共享内存来通信。 CSP 模型简介
CSP 模型由 Tony Hoare 在 20 世纪 70 年代提出是一种基于消息传递的并发模型。其核心思想是
通信代替共享并发实体如 Goroutine通过 Channel 进行通信而不是直接共享内存。Channel 是第一类对象Channel 是 CSP 模型的核心用于在并发实体之间传递消息。同步通信发送和接收操作是阻塞的确保消息的同步传递。
CSP 模型的优势在于
避免了传统多线程编程中的锁竞争问题。简化了并发编程的复杂性。提高了程序的可读性和可维护性。 Golang 中的 CSP 实现
Golang 通过 Goroutine 和 Channel 实现了 CSP 模型。
1. Goroutine
Goroutine 是 Golang 中的并发执行单位类似于线程但比线程更轻量。其特点包括
用户态调度Goroutine 由 Go 运行时调度避免了内核态和用户态的切换开销。低成本创建每个 Goroutine 的栈空间初始很小通常为 2KB可以轻松创建成千上万的 Goroutine。动态扩展Goroutine 的栈空间会根据需要动态扩展和收缩。
2. Channel
Channel 是 Goroutine 之间的通信机制用于传递数据。其特点包括
类型安全Channel 有明确的类型只能传递指定类型的数据。同步通信发送和接收操作是阻塞的确保数据的同步传递。双向或单向Channel 可以是双向的也可以是单向的只发送或只接收。 GPM 调度模型
Golang 的并发调度由 GPM 模型 实现即
GGoroutine用户级的轻量级线程每个 Goroutine 保存自己的上下文信息。PProcessor逻辑处理器负责调度 Goroutine 和线程M之间的关联关系。MMachine操作系统线程负责执行 Goroutine。
GPM 的工作原理
初始化Go 程序启动时会创建多个 P默认等于 CPU 核心数每个 P 绑定一个 M。Goroutine 调度 每个 P 维护一个本地 Goroutine 队列Local Runqueue。当一个 Goroutine 被创建时会被放入某个 P 的本地队列中。M 从绑定的 P 的本地队列中获取 Goroutine 并执行。 阻塞处理 如果 Goroutine 发生阻塞如 IO 操作M 会释放 PP 会绑定到另一个 M 继续执行其他 Goroutine。当阻塞的 Goroutine 恢复时会被放入全局队列Global Runqueue或某个 P 的本地队列中。 负载均衡 如果某个 P 的本地队列为空它会从全局队列或其他 P 的本地队列中“偷取” Goroutine。如果全局队列也为空M 会进入休眠状态直到有新的 Goroutine 被创建。 #mermaid-svg-Yxw0H80M4n0x9xk2 {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-Yxw0H80M4n0x9xk2 .error-icon{fill:#552222;}#mermaid-svg-Yxw0H80M4n0x9xk2 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-Yxw0H80M4n0x9xk2 .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-Yxw0H80M4n0x9xk2 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-Yxw0H80M4n0x9xk2 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-Yxw0H80M4n0x9xk2 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-Yxw0H80M4n0x9xk2 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-Yxw0H80M4n0x9xk2 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-Yxw0H80M4n0x9xk2 .marker.cross{stroke:#333333;}#mermaid-svg-Yxw0H80M4n0x9xk2 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-Yxw0H80M4n0x9xk2 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-Yxw0H80M4n0x9xk2 .cluster-label text{fill:#333;}#mermaid-svg-Yxw0H80M4n0x9xk2 .cluster-label span{color:#333;}#mermaid-svg-Yxw0H80M4n0x9xk2 .label text,#mermaid-svg-Yxw0H80M4n0x9xk2 span{fill:#333;color:#333;}#mermaid-svg-Yxw0H80M4n0x9xk2 .node rect,#mermaid-svg-Yxw0H80M4n0x9xk2 .node circle,#mermaid-svg-Yxw0H80M4n0x9xk2 .node ellipse,#mermaid-svg-Yxw0H80M4n0x9xk2 .node polygon,#mermaid-svg-Yxw0H80M4n0x9xk2 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-Yxw0H80M4n0x9xk2 .node .label{text-align:center;}#mermaid-svg-Yxw0H80M4n0x9xk2 .node.clickable{cursor:pointer;}#mermaid-svg-Yxw0H80M4n0x9xk2 .arrowheadPath{fill:#333333;}#mermaid-svg-Yxw0H80M4n0x9xk2 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-Yxw0H80M4n0x9xk2 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-Yxw0H80M4n0x9xk2 .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-Yxw0H80M4n0x9xk2 .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-Yxw0H80M4n0x9xk2 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-Yxw0H80M4n0x9xk2 .cluster text{fill:#333;}#mermaid-svg-Yxw0H80M4n0x9xk2 .cluster span{color:#333;}#mermaid-svg-Yxw0H80M4n0x9xk2 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-Yxw0H80M4n0x9xk2 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 是 否 GPM 调度模型 G Goroutine P Processor M Machine 用户级轻量级线程 保存上下文信息 逻辑处理器 调度 Goroutine 和 M 的关系 操作系统线程 执行 Goroutine 维护本地 Goroutine 队列 从队列中获取 Goroutine 执行 Goroutine 是否阻塞? 释放 PM 绑定到其他 P 继续执行 阻塞恢复后放入全局队列 其他 P 从全局队列中偷取 Goroutine 以下是 Golang 中使用 Goroutine 和 Channel 实现并发通信的示例
package mainimport (fmttime
)func worker(id int, jobs -chan int, results chan- int) {for job : range jobs {fmt.Printf(Worker %d started job %d\n, id, job)time.Sleep(time.Second) // 模拟任务执行fmt.Printf(Worker %d finished job %d\n, id, job)results - job * 2 // 将结果发送到 results Channel}
}func main() {const numJobs 5jobs : make(chan int, numJobs)results : make(chan int, numJobs)// 启动 3 个 Worker Goroutinefor w : 1; w 3; w {go worker(w, jobs, results)}// 发送任务到 jobs Channelfor j : 1; j numJobs; j {jobs - j}close(jobs)// 从 results Channel 中接收结果for a : 1; a numJobs; a {fmt.Println(Result:, -results)}
}