2026-02-06 03:34:50 +08:00
< template >
< div class = "demo-container" >
< h4 > Go 协程 ( Goroutine ) 与 GMP 调度演示 < / h4 >
< div class = "controls" >
2026-02-18 17:38:10 +08:00
< el-radio-group
v-model = "viewMode"
size = "small"
>
< el-radio-button label = "overview" >
整体视图
< / el-radio-button >
< el-radio-button label = "gmp" >
GMP 调度
< / el-radio-button >
< el-radio-button label = "channel" >
Channel 通信
< / el-radio-button >
2026-02-06 03:34:50 +08:00
< / el-radio-group >
2026-02-18 17:38:10 +08:00
< el-button
type = "primary"
size = "small"
:disabled = "isRunning"
@click ="startDemo"
>
2026-02-06 03:34:50 +08:00
{ { isRunning ? '运行中...' : '开始演示' } }
< / el-button >
2026-02-18 17:38:10 +08:00
< el-button
size = "small"
: disabled = "goroutines.length >= 20"
@click ="addGoroutine"
>
2026-02-06 03:34:50 +08:00
+ Goroutine
< / el-button >
2026-02-18 17:38:10 +08:00
< el-button
size = "small"
@click ="reset"
>
重置
< / el-button >
2026-02-06 03:34:50 +08:00
< / div >
<!-- GMP 调度视图 -- >
2026-02-18 17:38:10 +08:00
< div
v-if = "viewMode === 'gmp' || viewMode === 'overview'"
class = "gmp-view"
>
2026-02-06 03:34:50 +08:00
< div class = "gmp-container" >
<!-- Global Queue -- >
< div class = "queue-section global-queue" >
< div class = "queue-header" >
< span class = "queue-name" > Global Queue ( G ) < / span >
2026-02-18 17:38:10 +08:00
< el-tag
size = "small"
type = "info"
>
{ { globalQueue . length } }
< / el-tag >
2026-02-06 03:34:50 +08:00
< / div >
< div class = "queue-content" >
2026-02-18 17:38:10 +08:00
< div
v-for = "g in globalQueue"
:key = "g.id"
class = "g-item"
: style = "{ backgroundColor: g.color }"
>
2026-02-06 03:34:50 +08:00
G { { g . id } }
< / div >
2026-02-18 17:38:10 +08:00
< div
v-if = "globalQueue.length === 0"
class = "empty-queue"
>
空
< / div >
2026-02-06 03:34:50 +08:00
< / div >
< / div >
<!-- P ( Processors ) -- >
< div class = "processors-section" >
< div class = "section-header" >
< span class = "section-name" > P ( Processors ) - { { processors . length } } 个 < / span >
< / div >
< div class = "processors-grid" >
2026-02-18 17:38:10 +08:00
< div
v-for = "(p, idx) in processors"
:key = "idx"
class = "processor"
2026-02-06 03:34:50 +08:00
: class = "{ 'active': p.active }"
2026-02-18 17:38:10 +08:00
: style = "{ borderColor: p.active ? p.color : '#e4e7ed' }"
>
2026-02-06 03:34:50 +08:00
< div class = "processor-header" >
< span class = "processor-name" > P { { idx } } < / span >
2026-02-18 17:38:10 +08:00
< span
class = "processor-status"
: class = "{ 'running': p.active }"
> { { p . active ? '运行中' : '空闲' } } < / span >
2026-02-06 03:34:50 +08:00
< / div >
< div class = "local-queue" >
2026-02-18 17:38:10 +08:00
< div class = "queue-label" >
本地队列
< / div >
2026-02-06 03:34:50 +08:00
< div class = "local-g-list" >
2026-02-18 17:38:10 +08:00
< div
v-for = "g in p.localQueue"
:key = "g.id"
class = "local-g-item"
: style = "{ backgroundColor: g.color }"
>
2026-02-06 03:34:50 +08:00
G { { g . id } }
< / div >
2026-02-18 17:38:10 +08:00
< div
v-if = "p.localQueue.length === 0"
class = "empty-local"
>
-
< / div >
2026-02-06 03:34:50 +08:00
< / div >
< / div >
2026-02-18 17:38:10 +08:00
< div
v-if = "p.m"
class = "m-binding"
>
2026-02-06 03:34:50 +08:00
< span class = "m-label" > 绑定 M { { p . m . id } } < / span >
< / div >
< / div >
< / div >
< / div >
<!-- M ( Machine Threads ) -- >
< div class = "machines-section" >
< div class = "section-header" >
< span class = "section-name" > M ( Machine Threads ) - { { machines . length } } 个 < / span >
< / div >
< div class = "machines-list" >
2026-02-18 17:38:10 +08:00
< div
v-for = "m in machines"
:key = "m.id"
class = "machine-item"
2026-02-06 03:34:50 +08:00
: class = "{ 'active': m.active }"
2026-02-18 17:38:10 +08:00
: style = "{ borderColor: m.active ? '#67c23a' : '#e4e7ed' }"
>
2026-02-06 03:34:50 +08:00
< span class = "machine-id" > M { { m . id } } < / span >
< span class = "machine-status" > { { m . active ? '运行中' : '休眠' } } < / span >
< / div >
< / div >
< / div >
< / div >
< / div >
< div class = "explanation" >
2026-02-18 17:38:10 +08:00
< el-alert
title = "GMP 调度模型"
type = "success"
2026-02-06 03:34:50 +08:00
:description = "gmpDescription"
2026-02-18 17:38:10 +08:00
show -icon
:closable = "false"
/ >
2026-02-06 03:34:50 +08:00
< / div >
< / div >
< / template >
< script setup >
2026-02-20 01:03:38 +08:00
import { ref , watch } from 'vue'
2026-02-06 03:34:50 +08:00
const gmpDescription = 'G (Goroutine): 待执行的任务。M (Machine): 操作系统线程,执行 G 的载体。P (Processor): 逻辑处理器,提供执行上下文。G 先放入 P 的本地队列,P 与 M 绑定后,M 从 P 获取 G 执行。当本地队列空时,会从全局队列或其他 P 偷任务。'
const viewMode = ref ( 'gmp' )
const isRunning = ref ( false )
const goroutines = ref ( [ ] )
// GMP 数据结构
const globalQueue = ref ( [ ] )
const processors = ref ( [ ] )
const machines = ref ( [ ] )
// 初始化数据
function initGMP ( ) {
// 创建一些 Goroutines
const colors = [ '#409eff' , '#67c23a' , '#e6a23c' , '#f56c6c' , '#909399' , '#b3d8ff' , '#c2e7b0' , '#f5dab1' ]
const goroutinesData = [ ]
for ( let i = 0 ; i < 12 ; i ++ ) {
goroutinesData . push ( {
id : i + 1 ,
color : colors [ i % colors . length ] ,
status : 'waiting'
} )
}
goroutines . value = goroutinesData
// 分配全局队列
globalQueue . value = goroutinesData . slice ( 0 , 3 )
// 初始化 Processors (P)
processors . value = [
{ id : 0 , active : true , color : '#409eff' , localQueue : goroutinesData . slice ( 3 , 6 ) , m : { id : 0 } } ,
{ id : 1 , active : false , color : '#67c23a' , localQueue : goroutinesData . slice ( 6 , 9 ) , m : null } ,
{ id : 2 , active : false , color : '#e6a23c' , localQueue : goroutinesData . slice ( 9 , 12 ) , m : null } ,
{ id : 3 , active : false , color : '#f56c6c' , localQueue : [ ] , m : null }
]
// 初始化 Machines (M)
machines . value = [
{ id : 0 , active : true } ,
{ id : 1 , active : false } ,
{ id : 2 , active : false } ,
{ id : 3 , active : false }
]
}
// 添加 Goroutine
function addGoroutine ( ) {
if ( goroutines . value . length >= 20 ) return
const colors = [ '#409eff' , '#67c23a' , '#e6a23c' , '#f56c6c' , '#909399' , '#b3d8ff' ]
const id = goroutines . value . length + 1
const newG = {
id ,
color : colors [ id % colors . length ] ,
status : 'waiting'
}
goroutines . value . push ( newG )
// 添加到第一个有空位的 P
for ( const p of processors . value ) {
if ( p . localQueue . length < 5 ) {
p . localQueue . push ( newG )
break
}
}
}
// 开始演示
function startDemo ( ) {
isRunning . value = true
// 模拟调度过程
let step = 0
const interval = setInterval ( ( ) => {
step ++
// 轮流激活 P
processors . value . forEach ( ( p , idx ) => {
p . active = ( idx === step % processors . value . length )
} )
// 对应的 M 也激活
machines . value . forEach ( ( m , idx ) => {
m . active = processors . value [ idx ] ? . active || false
} )
if ( step >= 20 ) {
clearInterval ( interval )
isRunning . value = false
}
} , 500 )
}
// 重置
function reset ( ) {
isRunning . value = false
initGMP ( )
}
// 监听视图模式变化
watch ( viewMode , ( ) => {
if ( viewMode . value === 'gmp' ) {
initGMP ( )
}
} )
// 初始化
initGMP ( )
< / script >
< style scoped >
. demo - container {
padding : 20 px ;
background : # f5f7fa ;
2026-02-14 20:23:34 +08:00
border - radius : 6 px ;
2026-02-06 03:34:50 +08:00
}
h4 {
margin : 0 0 16 px 0 ;
color : # 303133 ;
}
. controls {
display : flex ;
gap : 8 px ;
margin - bottom : 16 px ;
flex - wrap : wrap ;
align - items : center ;
}
. gmp - view {
background : white ;
2026-02-14 20:23:34 +08:00
border - radius : 6 px ;
2026-02-06 03:34:50 +08:00
padding : 16 px ;
margin - bottom : 16 px ;
}
. gmp - container {
display : flex ;
flex - direction : column ;
gap : 16 px ;
}
. queue - section {
background : # f5f7fa ;
2026-02-14 20:23:34 +08:00
border - radius : 6 px ;
2026-02-06 03:34:50 +08:00
padding : 12 px ;
}
. queue - header {
display : flex ;
justify - content : space - between ;
align - items : center ;
margin - bottom : 8 px ;
}
. queue - name {
font - weight : bold ;
color : # 303133 ;
}
. queue - content {
display : flex ;
flex - wrap : wrap ;
gap : 6 px ;
min - height : 40 px ;
align - items : center ;
}
. g - item {
padding : 4 px 8 px ;
border - radius : 4 px ;
color : white ;
font - size : 11 px ;
font - weight : bold ;
}
. empty - queue {
color : # 909399 ;
font - size : 12 px ;
text - align : center ;
width : 100 % ;
}
. processors - section ,
. machines - section {
background : # f5f7fa ;
2026-02-14 20:23:34 +08:00
border - radius : 6 px ;
2026-02-06 03:34:50 +08:00
padding : 12 px ;
}
. section - header {
margin - bottom : 12 px ;
}
. section - name {
font - weight : bold ;
color : # 303133 ;
font - size : 13 px ;
}
. processors - grid {
display : grid ;
grid - template - columns : repeat ( 4 , 1 fr ) ;
gap : 8 px ;
}
. processor {
background : white ;
border : 2 px solid # e4e7ed ;
2026-02-14 20:23:34 +08:00
border - radius : 6 px ;
2026-02-06 03:34:50 +08:00
padding : 10 px ;
transition : all 0.3 s ;
}
. processor . active {
box - shadow : 0 0 10 px currentColor ;
}
. processor - header {
display : flex ;
justify - content : space - between ;
align - items : center ;
margin - bottom : 8 px ;
}
. processor - name {
font - weight : bold ;
font - size : 12 px ;
color : # 303133 ;
}
. processor - status {
font - size : 10 px ;
padding : 2 px 6 px ;
border - radius : 10 px ;
background : # dcdfe6 ;
color : # 606266 ;
}
. processor - status . running {
background : # 67 c23a ;
color : white ;
}
. local - queue {
margin - bottom : 8 px ;
}
. queue - label {
font - size : 10 px ;
color : # 909399 ;
margin - bottom : 4 px ;
}
. local - g - list {
display : flex ;
flex - wrap : wrap ;
gap : 3 px ;
}
. local - g - item {
padding : 2 px 5 px ;
border - radius : 3 px ;
color : white ;
font - size : 9 px ;
font - weight : bold ;
}
. empty - local {
font - size : 10 px ;
color : # c0c4cc ;
}
. m - binding {
font - size : 10 px ;
color : # 409 eff ;
background : # ecf5ff ;
padding : 2 px 6 px ;
border - radius : 3 px ;
}
. m - label {
font - weight : 500 ;
}
. machines - list {
display : flex ;
flex - wrap : wrap ;
gap : 8 px ;
}
. machine - item {
background : white ;
border : 2 px solid # e4e7ed ;
border - radius : 6 px ;
padding : 8 px 12 px ;
display : flex ;
align - items : center ;
gap : 8 px ;
transition : all 0.3 s ;
}
. machine - item . active {
border - color : # 67 c23a ;
background : # f0f9eb ;
}
. machine - id {
font - weight : bold ;
font - size : 12 px ;
color : # 303133 ;
}
. machine - status {
font - size : 11 px ;
color : # 909399 ;
}
. machine - item . active . machine - status {
color : # 67 c23a ;
}
. explanation {
margin - top : 16 px ;
}
@ media ( max - width : 768 px ) {
. processors - grid {
grid - template - columns : repeat ( 2 , 1 fr ) ;
}
}
< / style >