Files
test-repo/docs/.vitepress/theme/components/appendix/concurrency-models/AsyncAwaitDemo.vue
T
sanbuphy d35211071a style: update border-radius and padding values across components
- standardize border-radius from 8px to 6px for consistent styling
- adjust padding values from 1rem to 0.75rem for better visual hierarchy
- remove redundant overflow-y properties for cleaner code
2026-02-14 20:23:34 +08:00

402 lines
8.6 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div class="demo-container">
<h4>async/await 机制演示</h4>
<div class="controls">
<el-button type="primary" size="small" @click="runExample" :disabled="isRunning">
{{ isRunning ? '运行中...' : '运行示例' }}
</el-button>
<el-button size="small" @click="reset">重置</el-button>
<el-checkbox v-model="showDetails" size="small">显示详细信息</el-checkbox>
</div>
<div class="code-section">
<div class="code-block">
<div class="code-header">
<span class="code-title">Python asyncio 示例</span>
</div>
<pre class="code-content"><code><span class="keyword">import</span> asyncio
<span class="keyword">async def</span> <span class="function">fetch_data</span>(url):
<span class="comment"># await 挂起让出 CPU</span>
response = <span class="keyword">await</span> aiohttp.get(url)
<span class="comment"># I/O 完成后继续执行</span>
<span class="keyword">return</span> response.json()
<span class="keyword">async def</span> <span class="function">main</span>():
<span class="comment"># 并发执行</span>
tasks = [fetch_data(url) <span class="keyword">for</span> url <span class="keyword">in</span> urls]
results = <span class="keyword">await</span> asyncio.gather(*tasks)</code></pre>
</div>
</div>
<div class="visualization">
<div class="timeline-container">
<h5>执行时间线</h5>
<div class="timeline">
<div class="time-axis">
<div class="axis-label">0ms</div>
<div class="axis-label">50ms</div>
<div class="axis-label">100ms</div>
<div class="axis-label">150ms</div>
<div class="axis-label">200ms</div>
</div>
<div class="thread-rows">
<div class="thread-row">
<div class="row-label">事件循环</div>
<div class="row-track">
<div class="execution-segment event-loop" style="width: 100%;">
调度中
</div>
</div>
</div>
<div v-for="(task, idx) in tasks" :key="task.id" class="thread-row">
<div class="row-label">任务 {{ task.id }}</div>
<div class="row-track">
<template v-for="(segment, sidx) in task.segments" :key="sidx">
<div class="execution-segment"
:class="{ 'active': segment.type === 'active', 'io': segment.type === 'io' }"
:style="{ left: segment.start + '%', width: segment.width + '%', backgroundColor: segment.color }">
<span v-if="segment.width > 8" class="segment-label">
{{ segment.type === 'active' ? '执行' : 'I/O' }}
</span>
</div>
</template>
</div>
</div>
</div>
</div>
</div>
<div class="stats-grid">
<div class="stat-card">
<div class="stat-title">并发任务数</div>
<div class="stat-value">{{ tasks.length }}</div>
</div>
<div class="stat-card">
<div class="stat-title">总执行时间</div>
<div class="stat-value">{{ totalTime }}ms</div>
</div>
<div class="stat-card">
<div class="stat-title">I/O 等待时间</div>
<div class="stat-value">{{ ioWaitTime }}ms</div>
</div>
<div class="stat-card">
<div class="stat-title">CPU 利用率</div>
<div class="stat-value">{{ cpuUtilization }}%</div>
</div>
</div>
</div>
<div class="explanation">
<el-alert title="async/await 的优势" type="success"
description="当一个任务遇到 I/O 操作(如网络请求)时,await 会让出 CPU,事件循环调度其他任务执行。I/O 完成后,任务从断点恢复。这种方式让单个线程可以并发处理数千个任务。"
show-icon :closable="false" />
</div>
</div>
</template>
<script setup>
import { ref, computed, watch } from 'vue'
const comparisonMode = ref('memory')
const coroutineCount = ref(1000)
const isRunning = ref(false)
const showDetails = ref(false)
const tasks = ref([])
// 颜色
const colors = ['#409eff', '#67c23a', '#e6a23c', '#f56c6c', '#909399']
// 计算统计数据
const totalTime = computed(() => {
if (tasks.value.length === 0) return 0
// 模拟总时间
return Math.round(50 + tasks.value.length * 10)
})
const ioWaitTime = computed(() => {
return Math.round(totalTime.value * 0.6)
})
const cpuUtilization = computed(() => {
return Math.round(100 - (ioWaitTime.value / totalTime.value) * 100)
})
// 生成任务数据
function generateTasks() {
const count = Math.min(Math.floor(coroutineCount.value / 200), 5)
const newTasks = []
for (let i = 0; i < count; i++) {
const segments = []
let currentPos = 5
// 生成交替的执行和I/O段
for (let j = 0; j < 3; j++) {
// 执行段
const execWidth = 10 + Math.random() * 10
segments.push({
type: 'active',
start: currentPos,
width: execWidth,
color: colors[i % colors.length]
})
currentPos += execWidth
// I/O段
const ioWidth = 15 + Math.random() * 10
segments.push({
type: 'io',
start: currentPos,
width: ioWidth,
color: '#dcdfe6'
})
currentPos += ioWidth
}
newTasks.push({
id: i + 1,
segments,
state: 'ready'
})
}
tasks.value = newTasks
}
// 运行示例
function runExample() {
isRunning.value = true
generateTasks()
// 模拟运行
setTimeout(() => {
isRunning.value = false
}, 2000)
}
// 重置
function reset() {
tasks.value = []
isRunning.value = false
coroutineCount.value = 1000
}
// 监听协程数量变化
watch(coroutineCount, () => {
if (tasks.value.length > 0) {
generateTasks()
}
})
// 初始化
generateTasks()
</script>
<style scoped>
.demo-container {
padding: 20px;
background: #f5f7fa;
border-radius: 6px;
}
h4 {
margin: 0 0 16px 0;
color: #303133;
}
.controls {
display: flex;
gap: 16px;
align-items: center;
margin-bottom: 20px;
flex-wrap: wrap;
}
.slider-label {
font-size: 14px;
color: #606266;
min-width: 100px;
}
.code-section {
margin-bottom: 20px;
}
.code-block {
background: #282c34;
border-radius: 6px;
overflow: hidden;
}
.code-header {
background: #21252b;
padding: 8px 16px;
border-bottom: 1px solid #181a1f;
}
.code-title {
color: #abb2bf;
font-size: 13px;
font-weight: 500;
}
.code-content {
padding: 16px;
margin: 0;
overflow-x: auto;
font-family: 'Fira Code', 'Consolas', monospace;
font-size: 13px;
line-height: 1.6;
}
.keyword {
color: #c678dd;
}
.function {
color: #61afef;
}
.comment {
color: #5c6370;
font-style: italic;
}
.visualization {
margin-bottom: 20px;
}
.timeline-container {
background: white;
border-radius: 6px;
padding: 16px;
margin-bottom: 16px;
}
.timeline-container h5 {
margin: 0 0 12px 0;
color: #303133;
}
.timeline {
position: relative;
}
.time-axis {
display: flex;
justify-content: space-between;
padding: 8px 0;
border-bottom: 1px solid #e4e7ed;
margin-bottom: 8px;
}
.axis-label {
font-size: 11px;
color: #909399;
}
.thread-rows {
display: flex;
flex-direction: column;
gap: 8px;
}
.thread-row {
display: grid;
grid-template-columns: 100px 1fr;
gap: 8px;
align-items: center;
}
.row-label {
font-size: 12px;
color: #606266;
text-align: right;
}
.row-track {
position: relative;
height: 24px;
background: #f5f7fa;
border-radius: 4px;
overflow: hidden;
}
.execution-segment {
position: absolute;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
font-size: 10px;
color: white;
font-weight: 500;
}
.execution-segment.io {
background: #dcdfe6 !important;
color: #606266;
}
.execution-segment.event-loop {
background: #409eff;
}
.current-indicator {
position: absolute;
top: 0;
bottom: 0;
width: 2px;
background: #f56c6c;
}
.stats-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 12px;
}
.stat-card {
background: white;
border-radius: 6px;
padding: 12px;
text-align: center;
}
.stat-title {
font-size: 12px;
color: #909399;
margin-bottom: 4px;
}
.stat-value {
font-size: 20px;
font-weight: bold;
color: #303133;
}
.explanation {
margin-top: 16px;
}
@media (max-width: 768px) {
.stats-grid {
grid-template-columns: repeat(2, 1fr);
}
.controls {
flex-direction: column;
align-items: stretch;
}
.thread-row {
grid-template-columns: 60px 1fr;
}
}
</style>