第45节:分布式渲染:Web Workers多线程渲染优化
概述
随着Web应用复杂度的增加,单线程渲染已成为性能瓶颈。分布式渲染通过Web Workers将计算任务分发到多个线程,充分利用多核CPU优势,显著提升渲染性能。

分布式渲染架构:
主线程 任务调度器 几何处理Worker 物理计算Worker 光照计算Worker 后期处理Worker 顶点处理 几何变换 LOD计算 碰撞检测 物理模拟 约束求解 阴影计算 光照烘焙 全局光照 效果合成 色调映射 抗锯齿 结果收集器 最终渲染
核心原理
Web Workers通信模式
| 通信模式 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| Transferable Objects | 大数据传输 | 零拷贝,高性能 | 数据所有权转移 |
| SharedArrayBuffer | 多线程共享数据 | 真正共享内存 | 需要同步机制 |
| MessageChannel | 双向通信 | 灵活,支持多通道 | 序列化开销 |
| BroadcastChannel | 广播通信 | 一对多通信 | 所有Worker都能接收 |
任务分割策略
javascript
// 任务分割配置
class TaskScheduler {
static createRenderTasks(scene, camera, renderer, workerCount) {
const tasks = [];
const objects = scene.getVisibleObjects(camera);
const objectsPerWorker = Math.ceil(objects.length / workerCount);
for (let i = 0; i < workerCount; i++) {
const start = i * objectsPerWorker;
const end = Math.min(start + objectsPerWorker, objects.length);
const workerObjects = objects.slice(start, end);
tasks.push({
workerId: i,
objects: workerObjects,
camera: camera.clone(),
viewport: this.calculateViewport(i, workerCount),
dependencies: this.calculateDependencies(i, workerCount)
});
}
return tasks;
}
static calculateViewport(workerIndex, totalWorkers) {
const width = 1.0 / totalWorkers;
const x = workerIndex * width;
return { x, y: 0, width, height: 1.0 };
}
}
完整代码实现
分布式渲染系统
vue
<template>
<div class="distributed-rendering-container">
<!-- 主渲染视图 -->
<div class="render-view">
<canvas ref="mainCanvas" class="main-canvas"></canvas>
<!-- Worker状态监控 -->
<div class="worker-monitor">
<div class="monitor-panel">
<h4>Worker状态监控</h4>
<div class="worker-grid">
<div v-for="worker in workerStatus"
:key="worker.id"
:class="['worker-status', worker.status]">
<div class="worker-header">
<span class="worker-name">{{ worker.name }}</span>
<span class="worker-indicator">{{ worker.indicator }}</span>
</div>
<div class="worker-stats">
<div class="stat">任务: {{ worker.tasksCompleted }}</div>
<div class="stat">内存: {{ worker.memory }} MB</div>
<div class="stat">负载: {{ worker.load }}%</div>
</div>
</div>
</div>
</div>
<div class="performance-panel">
<h4>性能统计</h4>
<div class="performance-stats">
<div class="perf-item">
<span>主线程帧率:</span>
<span>{{ mainFPS }} FPS</span>
</div>
<div class="perf-item">
<span>Worker帧率:</span>
<span>{{ workerFPS }} FPS</span>
</div>
<div class="perf-item">
<span>通信开销:</span>
<span>{{ communicationOverhead }}ms</span>
</div>
<div class="perf-item">
<span>并行加速比:</span>
<span>{{ speedupRatio }}x</span>
</div>
</div>
</div>
</div>
</div>
<!-- 控制面板 -->
<div class="control-panel">
<div class="panel-section">
<h3>🔧 Worker配置</h3>
<div class="worker-config">
<div class="config-group">
<label>Worker数量</label>
<select v-model="workerCount" @change="reinitializeWorkers">
<option value="2">2 Workers</option>
<option value="4">4 Workers</option>
<option value="8">8 Workers</option>
<option value="auto">自动检测</option>
</select>
</div>
<div class="config-group">
<label>任务分配策略</label>
<select v-model="taskStrategy">
<option value="spatial">空间分割</option>
<option value="object">物体分割</option>
<option value="hybrid">混合分割</option>
</select>
</div>
<div class="config-group">
<label>通信模式</label>
<select v-model="communicationMode">
<option value="transferable">Transferable Objects</option>
<option value="shared">SharedArrayBuffer</option>
<option value="message">MessageChannel</option>
</select>
</div>
</div>
</div>
<div class="panel-section">
<h3>⚡ 渲染优化</h3>
<div class="optimization-controls">
<div class="control-group">
<label>
<input type="checkbox" v-model="enableGeometryWorker">
几何处理Worker
</label>
</div>
<div class="control-group">
<label>
<input type="checkbox" v-model="enableLightingWorker">
光照计算Worker
</label>
</div>
<div class="control-group">
<label>
<input type="checkbox" v-model="enablePhysicsWorker">
物理计算Worker
</label>
</div>
<div class="control-group">
<label>
<input type="checkbox" v-model="enablePostProcessingWorker">
后期处理Worker
</label>
</div>
<div class="control-group">
<label>任务粒度</label>
<input type="range" v-model="taskGranularity" min="1" max="10">
<span>{{ taskGranularity }}</span>
</div>
</div>
</div>
<div class="panel-section">
<h3>📊 负载均衡</h3>
<div class="load-balancing">
<div class="balance-controls">
<div class="control-group">
<label>动态负载均衡</label>
<input type="checkbox" v-model="dynamicLoadBalancing">
</div>
<div class="control-group">
<label>均衡频率</label>
<input type="range" v-model="balanceFrequency" min="1" max="60">
<span>{{ balanceFrequency }}帧</span>
</div>
<div class="control-group">
<label>负载阈值</label>
<input type="range" v-model="loadThreshold" min="50" max="95">
<span>{{ loadThreshold }}%</span>
</div>
</div>
<div class="load-distribution">
<h5>负载分布</h5>
<div class="distribution-bars">
<div v-for="worker in workerStatus"
:key="worker.id"
class="distribution-bar">
<div class="bar-label">{{ worker.name }}</div>
<div class="bar-container">
<div class="bar-fill" :style="{ width: worker.load + '%' }"></div>
</div>
<div class="bar-value">{{ worker.load }}%</div>
</div>
</div>
</div>
</div>
</div>
<div class="panel-section">
<h3>🎮 场景控制</h3>
<div class="scene-controls">
<div class="control-group">
<label>场景复杂度</label>
<select v-model="sceneComplexity" @change="updateScene">
<option value="low">低 (1K物体)</option>
<option value="medium">中 (10K物体)</option>
<option value="high">高 (100K物体)</option>
</select>
</div>
<div class="control-group">
<label>渲染模式</label>
<select v-model="renderMode" @change="toggleRenderMode">
<option value="single">单线程</option>
<option value="multi">多线程</option>
<option value="hybrid">混合模式</option>
</select>
</div>
<div class="control-buttons">
<button @click="startWorkers" class="control-button" :disabled="workersRunning">
▶️ 启动Workers
</button>
<button @click="stopWorkers" class="control-button" :disabled="!workersRunning">
⏹️ 停止Workers
</button>
<button @click="resetScene" class="control-button">
🔄 重置场景
</button>
</div>
</div>
</div>
</div>
<!-- 通信监控 -->
<div v-if="showCommunicationMonitor" class="communication-monitor">
<div class="monitor-header">
<h4>线程通信监控</h4>
<button @click="showCommunicationMonitor = false" class="close-button">×</button>
</div>
<div class="communication-logs">
<div v-for="log in communicationLogs"
:key="log.id"
:class="['log-entry', log.type]">
<span class="log-time">{{ log.timestamp }}</span>
<span class="log-direction">{{ log.direction }}</span>
<span class="log-message">{{ log.message }}</span>
<span class="log-size">{{ log.size }} KB</span>
</div>
</div>
</div>
</div>
</template>
<script>
import { onMounted, onUnmounted, ref, reactive, computed } from 'vue';
import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
// Worker管理器
class WorkerManager {
constructor() {
this.workers = new Map();
this.taskQueue = new Map();
this.results = new Map();
this.workerScripts = new Map();
this.setupWorkerScripts();
}
setupWorkerScripts() {
// 注册不同类型的Worker
this.workerScripts.set('geometry', this.createGeometryWorkerScript());
this.workerScripts.set('lighting', this.createLightingWorkerScript());
this.workerScripts.set('physics', this.createPhysicsWorkerScript());
this.workerScripts.set('postprocess', this.createPostProcessWorkerScript());
}
// 初始化Workers
async initializeWorkers(count, types = ['geometry', 'lighting', 'physics', 'postprocess']) {
this.terminateAllWorkers();
const cpuCores = navigator.hardwareConcurrency || 4;
const actualCount = count === 'auto' ? Math.min(cpuCores, types.length) : parseInt(count);
for (let i = 0; i < actualCount; i++) {
const workerType = types[i % types.length];
const worker = await this.createWorker(workerType, i);
this.workers.set(worker.id, worker);
}
return Array.from(this.workers.values());
}
// 创建Worker
createWorker(type, id) {
return new Promise((resolve) => {
const blob = new Blob([this.workerScripts.get(type)], { type: 'application/javascript' });
const workerUrl = URL.createObjectURL(blob);
const worker = new Worker(workerUrl);
worker.id = `worker_${type}_${id}`;
worker.type = type;
worker.status = 'idle';
worker.tasksCompleted = 0;
// 设置消息处理器
worker.onmessage = (event) => {
this.handleWorkerMessage(worker, event);
};
worker.onerror = (error) => {
console.error(`Worker ${worker.id} 错误:`, error);
worker.status = 'error';
};
resolve(worker);
});
}
// 处理Worker消息
handleWorkerMessage(worker, event) {
const { type, taskId, result, error, performance } = event.data;
switch (type) {
case 'ready':
worker.status = 'ready';
break;
case 'task_complete':
worker.status = 'idle';
worker.tasksCompleted++;
this.results.set(taskId, result);
this.taskQueue.delete(taskId);
// 触发任务完成回调
if (this.onTaskComplete) {
this.onTaskComplete(taskId, result, performance);
}
break;
case 'error':
worker.status = 'error';
console.error(`Worker ${worker.id} 任务错误:`, error);
break;
}
}
// 分配任务
assignTask(workerId, task) {
const worker = this.workers.get(workerId);
if (!worker || worker.status !== 'idle') return false;
worker.status = 'working';
const taskId = this.generateTaskId();
this.taskQueue.set(taskId, {
workerId,
task,
startTime: performance.now()
});
// 使用Transferable Objects优化大数据传输
const transferables = this.prepareTransferableObjects(task);
worker.postMessage({
type: 'execute_task',
taskId,
task
}, transferables);
return taskId;
}
// 准备可传输对象
prepareTransferableObjects(task) {
const transferables = [];
if (task.geometryData && task.geometryData.vertices) {
transferables.push(task.geometryData.vertices.buffer);
}
if (task.textureData) {
transferables.push(task.textureData.buffer);
}
return transferables;
}
// 智能任务调度
scheduleTask(task) {
// 找到最适合的Worker
const suitableWorkers = this.findSuitableWorkers(task.type);
if (suitableWorkers.length === 0) return null;
// 选择负载最低的Worker
const bestWorker = suitableWorkers.reduce((prev, current) =>
prev.load < current.load ? prev : current
);
return this.assignTask(bestWorker.id, task);
}
// 查找合适的Worker
findSuitableWorkers(taskType) {
return Array.from(this.workers.values()).filter(worker =>
worker.status === 'idle' &&
(worker.type === taskType || worker.type === 'general')
);
}
generateTaskId() {
return `task_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
}
// 终止所有Worker
terminateAllWorkers() {
for (const worker of this.workers.values()) {
worker.terminate();
}
this.workers.clear();
this.taskQueue.clear();
this.results.clear();
}
// 创建Worker脚本
createGeometryWorkerScript() {
return `
importScripts('https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js');
let scene, camera;
const geometries = new Map();
self.onmessage = function(event) {
const { type, taskId, task } = event.data;
switch (type) {
case 'execute_task':
handleGeometryTask(taskId, task);
break;
}
};
function handleGeometryTask(taskId, task) {
const startTime = performance.now();
try {
// 处理几何数据
const result = processGeometryData(task.geometryData, task.operations);
const processingTime = performance.now() - startTime;
self.postMessage({
type: 'task_complete',
taskId,
result,
performance: {
processingTime,
memory: getMemoryUsage()
}
});
} catch (error) {
self.postMessage({
type: 'error',
taskId,
error: error.message
});
}
}
function processGeometryData(geometryData, operations) {
// 创建BufferGeometry
const geometry = new THREE.BufferGeometry();
if (geometryData.vertices) {
const vertices = new Float32Array(geometryData.vertices);
geometry.setAttribute('position', new THREE.BufferAttribute(vertices, 3));
}
if (geometryData.normals) {
const normals = new Float32Array(geometryData.normals);
geometry.setAttribute('normal', new THREE.BufferAttribute(normals, 3));
}
// 应用几何操作
if (operations.transform) {
applyTransform(geometry, operations.transform);
}
if (operations.lod) {
applyLOD(geometry, operations.lod);
}
// 计算边界体积
geometry.computeBoundingSphere();
geometry.computeBoundingBox();
return {
geometry: serializeGeometry(geometry),
bounds: {
boundingSphere: geometry.boundingSphere,
boundingBox: geometry.boundingBox
}
};
}
function serializeGeometry(geometry) {
// 简化几何体序列化
const attributes = {};
for (const [name, attribute] of Object.entries(geometry.attributes)) {
attributes[name] = {
array: attribute.array,
itemSize: attribute.itemSize,
normalized: attribute.normalized
};
}
return {
attributes,
index: geometry.index ? geometry.index.array : null
};
}
function getMemoryUsage() {
return performance.memory ? (performance.memory.usedJSHeapSize / 1048576).toFixed(1) : 0;
}
// 通知主线程Worker已就绪
self.postMessage({ type: 'ready' });
`;
}
createLightingWorkerScript() {
return `
// 光照计算Worker实现
self.onmessage = function(event) {
const { type, taskId, task } = event.data;
if (type === 'execute_task') {
handleLightingTask(taskId, task);
}
};
function handleLightingTask(taskId, task) {
// 光照计算逻辑
const result = calculateLighting(task.sceneData, task.lights, task.materials);
self.postMessage({
type: 'task_complete',
taskId,
result
});
}
function calculateLighting(sceneData, lights, materials) {
// 简化光照计算
return {
lightingData: new Float32Array(sceneData.vertexCount * 3),
shadows: new Uint8Array(sceneData.vertexCount)
};
}
`;
}
createPhysicsWorkerScript() {
return `
// 物理计算Worker实现
importScripts('https://cdn.jsdelivr.net/npm/ammo.js@1.0.0/builds/ammo.wasm.js');
let physicsWorld;
self.onmessage = async function(event) {
const { type, taskId, task } = event.data;
if (type === 'execute_task') {
await handlePhysicsTask(taskId, task);
}
};
async function handlePhysicsTask(taskId, task) {
if (!physicsWorld) {
await initPhysics();
}
// 物理模拟逻辑
const result = simulatePhysics(task.bodies, task.constraints, task.deltaTime);
self.postMessage({
type: 'task_complete',
taskId,
result
});
}
async function initPhysics() {
// 初始化物理引擎
// 简化实现
}
`;
}
createPostProcessWorkerScript() {
return `
// 后期处理Worker实现
self.onmessage = function(event) {
const { type, taskId, task } = event.data;
if (type === 'execute_task') {
handlePostProcessTask(taskId, task);
}
};
function handlePostProcessTask(taskId, task) {
const result = applyPostProcessing(
task.imageData,
task.effects,
task.parameters
);
self.postMessage({
type: 'task_complete',
taskId,
result
}, [result.buffer]); // 传输结果缓冲区
}
function applyPostProcessing(imageData, effects, parameters) {
// 后期处理效果应用
const processedData = new Uint8ClampedArray(imageData.data);
effects.forEach(effect => {
switch (effect) {
case 'bloom':
applyBloom(processedData, parameters);
break;
case 'ssao':
applySSAO(processedData, parameters);
break;
case 'colorGrading':
applyColorGrading(processedData, parameters);
break;
}
});
return processedData;
}
`;
}
}
// 分布式渲染器
class DistributedRenderer {
constructor(mainRenderer, workerManager) {
this.mainRenderer = mainRenderer;
this.workerManager = workerManager;
this.renderTasks = new Map();
this.partialResults = new Map();
this.setupWorkerCallbacks();
}
setupWorkerCallbacks() {
this.workerManager.onTaskComplete = (taskId, result, performance) => {
this.handleTaskResult(taskId, result, performance);
};
}
// 分布式渲染
async renderDistributed(scene, camera) {
const startTime = performance.now();
// 分割渲染任务
const tasks = this.splitRenderTasks(scene, camera);
const taskPromises = [];
// 分配任务给Workers
for (const task of tasks) {
const taskId = this.workerManager.scheduleTask(task);
if (taskId) {
taskPromises.push(this.waitForTask(taskId));
}
}
// 等待所有任务完成
await Promise.all(taskPromises);
// 合成最终结果
const finalResult = this.composeResults();
const renderTime = performance.now() - startTime;
return { finalResult, renderTime, taskCount: tasks.length };
}
// 分割渲染任务
splitRenderTasks(scene, camera) {
const tasks = [];
const visibleObjects = this.getVisibleObjects(scene, camera);
const workerCount = this.workerManager.workers.size;
// 基于空间分割任务
if (this.taskStrategy === 'spatial') {
const spatialTasks = this.createSpatialTasks(scene, camera, workerCount);
tasks.push(...spatialTasks);
}
// 基于物体分割任务
else if (this.taskStrategy === 'object') {
const objectTasks = this.createObjectTasks(visibleObjects, workerCount);
tasks.push(...objectTasks);
}
return tasks;
}
// 创建空间分割任务
createSpatialTasks(scene, camera, workerCount) {
const tasks = [];
const frustum = new THREE.Frustum();
const projectionMatrix = new THREE.Matrix4().multiplyMatrices(
camera.projectionMatrix, camera.matrixWorldInverse
);
frustum.setFromProjectionMatrix(projectionMatrix);
// 将视锥体分割为多个子区域
for (let i = 0; i < workerCount; i++) {
const subFrustum = this.createSubFrustum(frustum, i, workerCount);
const taskObjects = this.getObjectsInFrustum(scene, subFrustum);
tasks.push({
type: 'render',
workerType: 'geometry',
objects: taskObjects,
camera: this.cloneCamera(camera),
viewport: this.calculateViewport(i, workerCount),
frustum: subFrustum
});
}
return tasks;
}
// 处理任务结果
handleTaskResult(taskId, result, performance) {
this.partialResults.set(taskId, result);
// 记录性能数据
this.performanceStats.push({
taskId,
workerId: this.workerManager.taskQueue.get(taskId)?.workerId,
...performance
});
}
// 等待任务完成
waitForTask(taskId) {
return new Promise((resolve) => {
const checkResult = () => {
if (this.partialResults.has(taskId)) {
resolve(this.partialResults.get(taskId));
} else {
setTimeout(checkResult, 1);
}
};
checkResult();
});
}
// 合成结果
composeResults() {
const finalCanvas = document.createElement('canvas');
const context = finalCanvas.getContext('2d');
finalCanvas.width = this.mainRenderer.domElement.width;
finalCanvas.height = this.mainRenderer.domElement.height;
// 合并所有部分渲染结果
for (const [taskId, result] of this.partialResults) {
if (result.imageData) {
this.mergeImageData(context, result.imageData, result.viewport);
}
}
this.partialResults.clear();
return finalCanvas;
}
mergeImageData(context, imageData, viewport) {
const tempCanvas = document.createElement('canvas');
const tempContext = tempCanvas.getContext('2d');
tempCanvas.width = imageData.width;
tempCanvas.height = imageData.height;
tempContext.putImageData(imageData, 0, 0);
context.drawImage(
tempCanvas,
viewport.x * context.canvas.width,
viewport.y * context.canvas.height,
viewport.width * context.canvas.width,
viewport.height * context.canvas.height
);
}
}
export default {
name: 'DistributedRendering',
setup() {
// 响应式状态
const mainCanvas = ref(null);
const workerCount = ref('4');
const taskStrategy = ref('spatial');
const communicationMode = ref('transferable');
const enableGeometryWorker = ref(true);
const enableLightingWorker = ref(true);
const enablePhysicsWorker = ref(false);
const enablePostProcessingWorker = ref(false);
const taskGranularity = ref(5);
const dynamicLoadBalancing = ref(true);
const balanceFrequency = ref(30);
const loadThreshold = ref(80);
const sceneComplexity = ref('medium');
const renderMode = ref('multi');
const showCommunicationMonitor = ref(false);
// Worker状态
const workerStatus = ref([]);
const workersRunning = ref(false);
// 性能统计
const mainFPS = ref(0);
const workerFPS = ref(0);
const communicationOverhead = ref(0);
const speedupRatio = ref(1);
// 通信日志
const communicationLogs = ref([]);
// Three.js 和 Worker 对象
let renderer, scene, camera, controls;
let workerManager, distributedRenderer;
let animationFrameId;
let frameCount = 0;
let lastFpsUpdate = 0;
// 初始化
const init = async () => {
await initRenderer();
initScene();
await initWorkers();
startAnimationLoop();
};
// 初始化渲染器
const initRenderer = () => {
renderer = new THREE.WebGLRenderer({
canvas: mainCanvas.value,
antialias: true,
powerPreference: "high-performance"
});
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
};
// 初始化场景
const initScene = () => {
scene = new THREE.Scene();
scene.background = new THREE.Color(0x1a1a2e);
camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set(0, 10, 20);
controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
// 照明
const ambientLight = new THREE.AmbientLight(0x404040, 0.6);
scene.add(ambientLight);
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);
directionalLight.position.set(50, 50, 25);
scene.add(directionalLight);
// 创建测试场景
createTestScene();
};
// 初始化Workers
const initWorkers = async () => {
workerManager = new WorkerManager();
const workerTypes = [];
if (enableGeometryWorker.value) workerTypes.push('geometry');
if (enableLightingWorker.value) workerTypes.push('lighting');
if (enablePhysicsWorker.value) workerTypes.push('physics');
if (enablePostProcessingWorker.value) workerTypes.push('postprocess');
const workers = await workerManager.initializeWorkers(workerCount.value, workerTypes);
// 初始化Worker状态监控
updateWorkerStatus(workers);
distributedRenderer = new DistributedRenderer(renderer, workerManager);
};
// 重新初始化Workers
const reinitializeWorkers = async () => {
await initWorkers();
};
// 创建测试场景
const createTestScene = () => {
// 创建地面
const groundGeometry = new THREE.PlaneGeometry(50, 50);
const groundMaterial = new THREE.MeshStandardMaterial({ color: 0x3a3a3a });
const ground = new THREE.Mesh(groundGeometry, groundMaterial);
ground.rotation.x = -Math.PI / 2;
ground.receiveShadow = true;
scene.add(ground);
// 根据复杂度创建物体
const objectCount = getObjectCount(sceneComplexity.value);
for (let i = 0; i < objectCount; i++) {
const object = createRandomObject();
scene.add(object);
}
};
// 获取物体数量
const getObjectCount = (complexity) => {
const counts = {
low: 1000,
medium: 10000,
high: 100000
};
return counts[complexity] || 1000;
};
// 创建随机物体
const createRandomObject = () => {
const geometries = [
() => new THREE.BoxGeometry(1, 1, 1),
() => new THREE.SphereGeometry(0.5, 8, 6),
() => new THREE.ConeGeometry(0.5, 1, 8)
];
const geometry = geometries[Math.floor(Math.random() * geometries.length)]();
const material = new THREE.MeshStandardMaterial({
color: new THREE.Color().setHSL(Math.random(), 0.7, 0.5)
});
const mesh = new THREE.Mesh(geometry, material);
mesh.position.set(
(Math.random() - 0.5) * 40,
Math.random() * 10 + 1,
(Math.random() - 0.5) * 40
);
mesh.rotation.set(
Math.random() * Math.PI,
Math.random() * Math.PI,
Math.random() * Math.PI
);
mesh.castShadow = true;
return mesh;
};
// 更新Worker状态
const updateWorkerStatus = (workers) => {
workerStatus.value = workers.map(worker => ({
id: worker.id,
name: worker.id,
status: worker.status,
indicator: getStatusIndicator(worker.status),
tasksCompleted: worker.tasksCompleted,
memory: (Math.random() * 50 + 10).toFixed(1), // 模拟内存使用
load: Math.floor(Math.random() * 100) // 模拟负载
}));
};
// 获取状态指示器
const getStatusIndicator = (status) => {
const indicators = {
ready: '🟢',
working: '🟡',
idle: '⚪',
error: '🔴'
};
return indicators[status] || '⚪';
};
// 启动Workers
const startWorkers = () => {
workersRunning.value = true;
// 实际实现中会开始分配任务
};
// 停止Workers
const stopWorkers = () => {
workersRunning.value = false;
workerManager.terminateAllWorkers();
};
// 重置场景
const resetScene = () => {
// 清理场景并重新创建
while (scene.children.length > 0) {
const child = scene.children[0];
if (child.isMesh) {
child.geometry.dispose();
child.material.dispose();
}
scene.remove(child);
}
createTestScene();
};
// 切换渲染模式
const toggleRenderMode = () => {
// 实现渲染模式切换逻辑
};
// 更新场景
const updateScene = () => {
resetScene();
};
// 动画循环
const startAnimationLoop = () => {
const animate = () => {
animationFrameId = requestAnimationFrame(animate);
// 更新控制
controls.update();
// 性能统计
updatePerformanceStats();
// 渲染
if (renderMode.value === 'multi' && workersRunning.value) {
// 分布式渲染
renderDistributed();
} else {
// 单线程渲染
renderer.render(scene, camera);
}
};
animate();
};
// 分布式渲染
const renderDistributed = async () => {
const result = await distributedRenderer.renderDistributed(scene, camera);
// 使用Worker渲染结果
if (result.finalResult) {
const context = renderer.getContext();
context.drawImage(result.finalResult, 0, 0);
}
};
// 更新性能统计
const updatePerformanceStats = () => {
frameCount++;
const now = performance.now();
if (now - lastFpsUpdate >= 1000) {
mainFPS.value = Math.round((frameCount * 1000) / (now - lastFpsUpdate));
frameCount = 0;
lastFpsUpdate = now;
}
// 模拟Worker性能数据
workerFPS.value = Math.round(mainFPS.value * 0.8 + Math.random() * 10);
communicationOverhead.value = (Math.random() * 2).toFixed(1);
speedupRatio.value = (workerFPS.value / mainFPS.value).toFixed(1);
};
onMounted(() => {
init();
window.addEventListener('resize', handleResize);
});
onUnmounted(() => {
if (animationFrameId) {
cancelAnimationFrame(animationFrameId);
}
if (workerManager) {
workerManager.terminateAllWorkers();
}
if (renderer) {
renderer.dispose();
}
window.removeEventListener('resize', handleResize);
});
const handleResize = () => {
if (!camera || !renderer) return;
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);