外观
Electron 集成 WebAssembly
集成概述
Electron 与 WebAssembly 的集成将 Web 技术的快速开发能力与原生代码的高性能特性完美结合。这种集成模式允许开发者在 Electron 的渲染进程和主进程中直接调用编译为 WebAssembly 的 C/C++、Rust 或其他语言代码,实现对计算密集型任务、现有原生库和硬件加速功能的深度集成。
集成架构的核心在于通过 WebAssembly 运行时建立 JavaScript 与原生编译代码之间的高效执行环境:
Electron 应用 (JavaScript/TypeScript)
↑↓ WebAssembly JavaScript API
WebAssembly 运行时 (WASM 模块)
↑
编译后的原生代码 (C/C++/Rust)
↑
系统资源 (计算/内存/算法)WebAssembly 基础与工具链
WebAssembly 架构解析
WebAssembly 是一种可移植、体积小、加载快的二进制指令格式,为 Electron 应用提供了接近原生代码的执行性能。与传统的 JavaScript 相比,WebAssembly 在计算密集型任务上具有显著优势。
WebAssembly 在 Electron 中的执行流程:
源代码 (C/C++/Rust) → Emscripten 编译 → WASM 模块 + JavaScript 胶水代码
↓
Electron 加载执行
↓
JavaScript 与 WASM 交互Emscripten 工具链配置
Emscripten 是将 C/C++ 代码编译为 WebAssembly 的核心工具链。
javascript
// scripts/emscripten-setup.js
import { execSync } from 'child_process'
import { existsSync, mkdirSync } from 'fs'
class EmscriptenSetup {
constructor() {
this.checkPrerequisites()
}
checkPrerequisites() {
const prerequisites = {
'Emscripten': this.checkCommand('emcc --version'),
'Python': this.checkCommand('python --version'),
'Git': this.checkCommand('git --version'),
}
const missing = Object.entries(prerequisites)
.filter(([, exists]) => !exists)
.map(([name]) => name)
if (missing.length > 0) {
throw new Error(`缺少必要的开发环境: ${missing.join(', ')}`)
}
}
checkCommand(command) {
try {
execSync(command, { stdio: 'ignore' })
return true
} catch {
return false
}
}
async compileCToWasm(sourceFile, outputName, options = {}) {
const defaultOptions = {
optimization: '-O2',
wasm: true,
modularize: true,
exportFunctions: ['_malloc', '_free'],
memoryModel: 'MAXIMUM_MEMORY=512MB',
}
const mergedOptions = { ...defaultOptions, ...options }
const command = [
'emcc',
sourceFile,
`-o ${outputName}.js`,
`-s ${mergedOptions.memoryModel}`,
mergedOptions.optimization,
mergedOptions.wasm ? '-s WASM=1' : '',
mergedOptions.modularize ? '-s MODULARIZE=1' : '',
`-s EXPORTED_FUNCTIONS="[${mergedOptions.exportFunctions
.map((f) => `'${f}'`)
.join(',')}]"`,
"-s EXPORTED_RUNTIME_METHODS=\"['ccall', 'cwrap']\"",
]
.filter(Boolean)
.join(' ')
try {
console.log(`🔨 编译 ${sourceFile} 为 WebAssembly...`)
execSync(command, { stdio: 'inherit' })
console.log('✅ WebAssembly 编译成功')
} catch (error) {
console.error('❌ 编译失败:', error.message)
throw error
}
}
}
export const emscriptenSetup = new EmscriptenSetup()基础 C/C++ 模块开发
cpp
// wasm-modules/src/core-calculations.cpp
#include <emscripten.h>
#include <emscripten/bind.h>
#include <cmath>
#include <vector>
// 高性能数学计算函数
extern "C" {
EMSCRIPTEN_KEEPALIVE
double calculate_distance(double x1, double y1, double x2, double y2) {
return std::sqrt(std::pow(x2 - x1, 2) + std::pow(y2 - y1, 2));
}
EMSCRIPTEN_KEEPALIVE
int* fibonacci_sequence(int n) {
if (n <= 0) return nullptr;
int* sequence = (int*)malloc(n * sizeof(int));
if (sequence == nullptr) return nullptr;
if (n >= 1) sequence[0] = 0;
if (n >= 2) sequence[1] = 1;
for (int i = 2; i < n; i++) {
sequence[i] = sequence[i - 1] + sequence[i - 2];
}
return sequence;
}
EMSCRIPTEN_KEEPALIVE
void free_memory(void* pointer) {
free(pointer);
}
}
// 使用 emscripten::bind 进行 C++ 类导出
class MatrixCalculator {
private:
std::vector<std::vector<double>> data;
public:
MatrixCalculator(const std::vector<std::vector<double>>& input) : data(input) {}
std::vector<std::vector<double>> multiply(const std::vector<std::vector<double>>& other) {
size_t rows = data.size();
size_t cols = other[0].size();
size_t inner = other.size();
std::vector<std::vector<double>> result(rows, std::vector<double>(cols, 0.0));
for (size_t i = 0; i < rows; i++) {
for (size_t j = 0; j < cols; j++) {
for (size_t k = 0; k < inner; k++) {
result[i][j] += data[i][k] * other[k][j];
}
}
}
return result;
}
double determinant() {
// 简化的行列式计算实现
if (data.size() == 2 && data[0].size() == 2) {
return data[0][0] * data[1][1] - data[0][1] * data[1][0];
}
return 0.0;
}
};
// 绑定到 JavaScript
EMSCRIPTEN_BINDINGS(matrix_calculator) {
emscripten::class_<MatrixCalculator>("MatrixCalculator")
.constructor<const std::vector<std::vector<double>>&>()
.function("multiply", &MatrixCalculator::multiply)
.function("determinant", &MatrixCalculator::determinant);
}Electron 中的 WebAssembly 集成
基础 WASM 模块加载
在 Electron 中加载和初始化 WebAssembly 模块需要特定的模式和错误处理机制。
javascript
// lib/wasm-loader.js
import { readFile } from 'fs/promises'
import { join, dirname } from 'path'
import { fileURLToPath } from 'url'
class WASMLoader {
constructor() {
this.modules = new Map()
this.loadingPromises = new Map()
this.__dirname = dirname(fileURLToPath(import.meta.url))
}
async loadWASMModule(moduleName, wasmPath, jsPath) {
if (this.modules.has(moduleName)) {
return this.modules.get(moduleName)
}
if (this.loadingPromises.has(moduleName)) {
return this.loadingPromises.get(moduleName)
}
const loadPromise = this.initializeWASMModule(wasmPath, jsPath)
.then((module) => {
this.modules.set(moduleName, module)
this.loadingPromises.delete(moduleName)
console.log(`✅ WASM 模块加载成功: ${moduleName}`)
return module
})
.catch((error) => {
this.loadingPromises.delete(moduleName)
console.error(`❌ WASM 模块加载失败: ${moduleName}`, error)
throw error
})
this.loadingPromises.set(moduleName, loadPromise)
return loadPromise
}
async initializeWASMModule(wasmPath, jsPath) {
// 动态导入 Emscripten 生成的 JS 胶水代码
const moduleFactory = await import(jsPath)
const moduleConfig = {
wasmBinary: await this.loadWASMBinary(wasmPath),
onRuntimeInitialized: () => {
console.log('WASM 运行时初始化完成')
},
print: (text) => console.log(`WASM: ${text}`),
printErr: (text) => console.error(`WASM Error: ${text}`),
}
return moduleFactory(moduleConfig)
}
async loadWASMBinary(wasmPath) {
try {
const fullPath = join(this.__dirname, wasmPath)
const wasmBuffer = await readFile(fullPath)
return wasmBuffer
} catch (error) {
console.error('读取 WASM 二进制文件失败:', error)
throw error
}
}
async callWASMFunction(moduleName, functionName, ...args) {
const module = await this.getModule(moduleName)
if (!module[functionName]) {
throw new Error(`函数 ${functionName} 在模块 ${moduleName} 中不存在`)
}
try {
const result = module[functionName](...args)
return result
} catch (error) {
console.error(`WASM 函数调用失败 [${moduleName}.${functionName}]:`, error)
throw error
}
}
async getModule(moduleName) {
if (!this.modules.has(moduleName)) {
throw new Error(`WASM 模块未加载: ${moduleName}`)
}
return this.modules.get(moduleName)
}
// 内存管理辅助函数
createWASMMemory(module, initial = 256, maximum = 2048) {
return new WebAssembly.Memory({ initial, maximum })
}
// 在 JavaScript 和 WASM 之间传递数据
allocateString(module, str) {
const encoder = new TextEncoder()
const bytes = encoder.encode(str)
const ptr = module._malloc(bytes.length + 1)
module.HEAPU8.set(bytes, ptr)
module.HEAPU8[ptr + bytes.length] = 0 // null terminator
return { ptr, length: bytes.length }
}
freeString(module, ptr) {
if (module._free) {
module._free(ptr)
}
}
}
export const wasmLoader = new WASMLoader()预加载脚本集成
在 Electron 的预加载脚本中安全地暴露 WASM 功能给渲染进程。
javascript
// preload/wasm-preload.js
import { contextBridge, ipcRenderer } from 'electron'
import { wasmLoader } from '../lib/wasm-loader.js'
class WASMPreloadIntegration {
constructor() {
this.initialized = false
this.init()
}
async init() {
try {
// 预加载关键 WASM 模块
await this.preloadCriticalModules()
this.initialized = true
console.log('✅ WASM 预加载初始化完成')
} catch (error) {
console.error('❌ WASM 预加载初始化失败:', error)
}
}
async preloadCriticalModules() {
const criticalModules = [
{
name: 'mathEngine',
wasmPath: '../wasm/math-engine.wasm',
jsPath: '../wasm/math-engine.js',
},
{
name: 'imageProcessor',
wasmPath: '../wasm/image-processor.wasm',
jsPath: '../wasm/image-processor.js',
},
]
await Promise.all(
criticalModules.map(async ({ name, wasmPath, jsPath }) => {
await wasmLoader.loadWASMModule(name, wasmPath, jsPath)
})
)
}
exposeToRenderer() {
const wasmAPI = {
// 模块状态检查
isInitialized: () => this.initialized,
// 数学计算功能
calculateDistance: async (x1, y1, x2, y2) => {
return await wasmLoader.callWASMFunction(
'mathEngine',
'calculate_distance',
x1,
y1,
x2,
y2
)
},
fibonacciSequence: async (n) => {
const module = await wasmLoader.getModule('mathEngine')
const ptr = module._fibonacci_sequence(n)
if (!ptr) throw new Error('内存分配失败')
try {
const sequence = []
for (let i = 0; i < n; i++) {
sequence.push(module.HEAP32[ptr / 4 + i])
}
return sequence
} finally {
module._free_memory(ptr)
}
},
// 图像处理功能
processImage: async (imageData, width, height, operation) => {
return await wasmLoader.callWASMFunction(
'imageProcessor',
'process_image',
imageData,
width,
height,
operation
)
},
}
// 安全地暴露到渲染进程
contextBridge.exposeInMainWorld('wasmAPI', wasmAPI)
}
}
const wasmPreload = new WASMPreloadIntegration()
wasmPreload.exposeToRenderer()高级 WebAssembly 功能
复杂数据结构处理
处理 JavaScript 和 WebAssembly 之间的复杂数据交换。
javascript
// lib/wasm-data-exchange.js
export class WASMDataExchange {
constructor(wasmModule) {
this.module = wasmModule
this.allocations = new Set()
}
// 传输数组到 WASM
transferArrayToWASM(jsArray, dataType = 'float') {
const typeInfo = {
'int8': { heap: this.module.HEAP8, bytesPerElement: 1 },
'int16': { heap: this.module.HEAP16, bytesPerElement: 2 },
'int32': { heap: this.module.HEAP32, bytesPerElement: 4 },
'float': { heap: this.module.HEAPF32, bytesPerElement: 4 },
'double': { heap: this.module.HEAPF64, bytesPerElement: 8 },
}
const info = typeInfo[dataType]
if (!info) {
throw new Error(`不支持的数据类型: ${dataType}`)
}
const bytes = jsArray.length * info.bytesPerElement
const ptr = this.module._malloc(bytes)
if (!ptr) {
throw new Error('内存分配失败')
}
this.allocations.add(ptr)
info.heap.set(jsArray, ptr / info.bytesPerElement)
return { ptr, length: jsArray.length, dataType }
}
// 从 WASM 检索数组
retrieveArrayFromWASM(ptr, length, dataType = 'float') {
const typeInfo = {
'int8': { heap: this.module.HEAP8, bytesPerElement: 1 },
'int16': { heap: this.module.HEAP16, bytesPerElement: 2 },
'int32': { heap: this.module.HEAP32, bytesPerElement: 4 },
'float': { heap: this.module.HEAPF32, bytesPerElement: 4 },
'double': { heap: this.module.HEAPF64, bytesPerElement: 8 },
}
const info = typeInfo[dataType]
if (!info) {
throw new Error(`不支持的数据类型: ${dataType}`)
}
const result = []
const startIndex = ptr / info.bytesPerElement
for (let i = 0; i < length; i++) {
result.push(info.heap[startIndex + i])
}
return result
}
// 传输二维矩阵到 WASM
transferMatrixToWASM(matrix, dataType = 'float') {
const flattened = matrix.flat()
const arrayInfo = this.transferArrayToWASM(flattened, dataType)
return {
...arrayInfo,
rows: matrix.length,
cols: matrix[0].length,
}
}
// 处理字符串数据
transferStringToWASM(str) {
const encoder = new TextEncoder()
const bytes = encoder.encode(str)
const ptr = this.module._malloc(bytes.length + 1)
if (!ptr) {
throw new Error('字符串内存分配失败')
}
this.allocations.add(ptr)
this.module.HEAPU8.set(bytes, ptr)
this.module.HEAPU8[ptr + bytes.length] = 0 // Null terminator
return { ptr, length: bytes.length }
}
// 清理内存
free(ptr) {
if (this.allocations.has(ptr)) {
this.module._free(ptr)
this.allocations.delete(ptr)
}
}
// 清理所有分配的内存
cleanup() {
for (const ptr of this.allocations) {
this.module._free(ptr)
}
this.allocations.clear()
}
// 内存使用统计
getMemoryUsage() {
const memory =
this.module._get_memory_usage && this.module._get_memory_usage()
return {
allocations: this.allocations.size,
totalMemory: memory ? memory.total : '未知',
usedMemory: memory ? memory.used : '未知',
}
}
}性能优化与多线程
利用 WebAssembly 的多线程能力提升性能。
javascript
// lib/wasm-thread-manager.js
import { Worker } from 'worker_threads'
export class WASMThreadManager {
constructor() {
this.workers = new Map()
this.taskQueue = new Map()
this.workerScript = join(
dirname(fileURLToPath(import.meta.url)),
'wasm-worker.js'
)
}
// 创建专用 WASM 工作线程
async createWorker(workerId, moduleName, wasmPath, jsPath) {
const worker = new Worker(this.workerScript, {
workerData: {
workerId,
moduleName,
wasmPath,
jsPath,
},
})
this.workers.set(workerId, worker)
worker.on('message', (result) => {
this.handleWorkerResult(workerId, result)
})
worker.on('error', (error) => {
console.error(`WASM 工作线程错误 [${workerId}]:`, error)
this.workers.delete(workerId)
})
worker.on('exit', (code) => {
if (code !== 0) {
console.warn(`WASM 工作线程退出 [${workerId}], 代码: ${code}`)
}
this.workers.delete(workerId)
})
// 等待 worker 初始化完成
return new Promise((resolve) => {
worker.once('online', () => {
console.log(`✅ WASM 工作线程就绪: ${workerId}`)
resolve(workerId)
})
})
}
// 提交任务到工作线程
async submitTask(workerId, taskType, data, timeout = 30000) {
return new Promise((resolve, reject) => {
const taskId = `task-${Date.now()}-${Math.random()
.toString(36)
.substr(2, 9)}`
const timeoutId = setTimeout(() => {
reject(new Error(`WASM 任务执行超时: ${taskId}`))
this.taskQueue.delete(taskId)
}, timeout)
this.taskQueue.set(taskId, { resolve, reject, timeoutId })
const worker = this.workers.get(workerId)
if (!worker) {
reject(new Error(`WASM 工作线程不存在: ${workerId}`))
return
}
worker.postMessage({ taskId, taskType, data })
})
}
handleWorkerResult(workerId, result) {
const { taskId, data, error } = result
const task = this.taskQueue.get(taskId)
if (!task) {
console.warn(`未知任务 ID: ${taskId}`)
return
}
clearTimeout(task.timeoutId)
this.taskQueue.delete(taskId)
if (error) {
task.reject(new Error(error))
} else {
task.resolve(data)
}
}
// 并行处理批量数据
async processBatchData(workerId, dataArray, processFunction) {
const batchPromises = dataArray.map((data, index) =>
this.submitTask(workerId, processFunction, { data, index })
)
const results = await Promise.all(batchPromises)
return results.sort((a, b) => a.index - b.index).map((r) => r.result)
}
// 优雅关闭所有工作线程
async shutdown() {
const shutdownPromises = Array.from(this.workers.values()).map((worker) => {
return new Promise((resolve) => {
worker.once('exit', () => resolve())
worker.postMessage({ type: 'shutdown' })
// 强制终止(如果 5 秒内没有正常退出)
setTimeout(() => {
worker.terminate()
resolve()
}, 5000)
})
})
await Promise.all(shutdownPromises)
this.workers.clear()
this.taskQueue.clear()
console.log('✅ 所有 WASM 工作线程已关闭')
}
}javascript
// lib/wasm-worker.js
import { workerData, parentPort, isMainThread } from 'worker_threads'
import { wasmLoader } from './wasm-loader.js'
class WASMWorker {
constructor(workerId, moduleName, wasmPath, jsPath) {
this.workerId = workerId
this.moduleName = moduleName
this.wasmPath = wasmPath
this.jsPath = jsPath
this.module = null
this.isShuttingDown = false
this.initialize()
}
async initialize() {
try {
this.module = await wasmLoader.loadWASMModule(
this.moduleName,
this.wasmPath,
this.jsPath
)
console.log(`✅ WASM 工作线程初始化完成: ${this.workerId}`)
// 通知主线程初始化完成
if (parentPort) {
parentPort.postMessage({ type: 'initialized', workerId: this.workerId })
}
} catch (error) {
console.error(`WASM 工作线程初始化失败: ${this.workerId}`, error)
process.exit(1)
}
}
async processTask(taskType, data) {
if (this.isShuttingDown) {
throw new Error('工作线程正在关闭')
}
try {
switch (taskType) {
case 'matrix_multiply':
return await this.processMatrixMultiplication(data)
case 'image_filter':
return await this.processImageFilter(data)
case 'data_transform':
return await this.processDataTransform(data)
default:
throw new Error(`未知任务类型: ${taskType}`)
}
} catch (error) {
console.error(`WASM 任务处理失败 [${taskType}]:`, error)
throw error
}
}
async processMatrixMultiplication({ matrixA, matrixB }) {
const exchange = new WASMDataExchange(this.module)
try {
const matrixAInfo = exchange.transferMatrixToWASM(matrixA)
const matrixBInfo = exchange.transferMatrixToWASM(matrixB)
const resultPtr = this.module._multiply_matrices(
matrixAInfo.ptr,
matrixAInfo.rows,
matrixAInfo.cols,
matrixBInfo.ptr,
matrixBInfo.rows,
matrixBInfo.cols
)
const result = exchange.retrieveArrayFromWASM(
resultPtr,
matrixAInfo.rows * matrixBInfo.cols
)
// 重组为二维矩阵
const resultMatrix = []
for (let i = 0; i < matrixAInfo.rows; i++) {
resultMatrix.push(
result.slice(i * matrixBInfo.cols, (i + 1) * matrixBInfo.cols)
)
}
return resultMatrix
} finally {
exchange.cleanup()
}
}
async processImageFilter({ imageData, width, height, filterType }) {
const exchange = new WASMDataExchange(this.module)
try {
const imageInfo = exchange.transferArrayToWASM(imageData, 'int8')
const resultPtr = this.module._apply_image_filter(
imageInfo.ptr,
width,
height,
filterType
)
const resultData = exchange.retrieveArrayFromWASM(
resultPtr,
imageData.length,
'int8'
)
return resultData
} finally {
exchange.cleanup()
}
}
}
// 工作线程主逻辑
if (!isMainThread && parentPort) {
const worker = new WASMWorker(
workerData.workerId,
workerData.moduleName,
workerData.wasmPath,
workerData.jsPath
)
parentPort.on('message', async (message) => {
if (message.type === 'shutdown') {
worker.isShuttingDown = true
return
}
const { taskId, taskType, data } = message
try {
const result = await worker.processTask(taskType, data)
parentPort.postMessage({ taskId, data: result })
} catch (error) {
parentPort.postMessage({
taskId,
error: error.message,
})
}
})
}实际应用场景
图像处理与计算机视觉
cpp
// wasm-modules/src/image-processing.cpp
#include <emscripten.h>
#include <emscripten/bind.h>
#include <algorithm>
#include <vector>
extern "C" {
EMSCRIPTEN_KEEPALIVE
uint8_t* apply_grayscale_filter(uint8_t* imageData, int width, int height) {
int totalPixels = width * height * 4; // RGBA
uint8_t* result = (uint8_t*)malloc(totalPixels);
for (int i = 0; i < totalPixels; i += 4) {
uint8_t r = imageData[i];
uint8_t g = imageData[i + 1];
uint8_t b = imageData[i + 2];
// 灰度转换公式
uint8_t gray = (uint8_t)(0.299 * r + 0.587 * g + 0.114 * b);
result[i] = gray; // R
result[i + 1] = gray; // G
result[i + 2] = gray; // B
result[i + 3] = imageData[i + 3]; // Alpha
}
return result;
}
EMSCRIPTEN_KEEPALIVE
uint8_t* apply_gaussian_blur(uint8_t* imageData, int width, int height, float sigma) {
int totalPixels = width * height * 4;
uint8_t* result = (uint8_t*)malloc(totalPixels);
// 简化的高斯模糊实现
const int kernelSize = 5;
float kernel[kernelSize][kernelSize] = {
{1, 4, 7, 4, 1},
{4, 16, 26, 16, 4},
{7, 26, 41, 26, 7},
{4, 16, 26, 16, 4},
{1, 4, 7, 4, 1}
};
float kernelSum = 273.0f; // 核值总和
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
for (int channel = 0; channel < 4; channel++) {
float sum = 0.0f;
for (int ky = -2; ky <= 2; ky++) {
for (int kx = -2; kx <= 2; kx++) {
int px = std::min(std::max(x + kx, 0), width - 1);
int py = std::min(std::max(y + ky, 0), height - 1);
int pixelIndex = (py * width + px) * 4 + channel;
float weight = kernel[ky + 2][kx + 2] / kernelSum;
sum += imageData[pixelIndex] * weight;
}
}
int resultIndex = (y * width + x) * 4 + channel;
result[resultIndex] = (uint8_t)std::min(std::max(sum, 0.0f), 255.0f);
}
}
}
return result;
}
}
EMSCRIPTEN_BINDINGS(image_processing) {
emscripten::function("apply_grayscale_filter", &apply_grayscale_filter);
emscripten::function("apply_gaussian_blur", &apply_gaussian_blur);
}科学计算与数据分析
javascript
// applications/scientific-computing.js
import { wasmLoader } from '../lib/wasm-loader.js'
import { WASMDataExchange } from '../lib/wasm-data-exchange.js'
export class ScientificComputing {
constructor() {
this.module = null
this.initialized = false
}
async initialize() {
this.module = await wasmLoader.loadWASMModule(
'scientific',
'../wasm/scientific.wasm',
'../wasm/scientific.js'
)
this.exchange = new WASMDataExchange(this.module)
this.initialized = true
}
// 快速傅里叶变换
async fft(signalData) {
await this.ensureInitialized()
const signalInfo = this.exchange.transferArrayToWASM(signalData, 'float')
try {
const resultPtr = this.module._fft_transform(
signalInfo.ptr,
signalInfo.length
)
const result = this.exchange.retrieveArrayFromWASM(
resultPtr,
signalInfo.length,
'float'
)
// 转换为复数表示 [real, imag, real, imag, ...]
const complexResult = []
for (let i = 0; i < result.length; i += 2) {
complexResult.push({
real: result[i],
imag: result[i + 1],
})
}
return complexResult
} finally {
this.exchange.cleanup()
}
}
// 数值积分
async numericalIntegration(fn, a, b, steps = 1000) {
await this.ensureInitialized()
// 使用梯形法则进行数值积分
const stepSize = (b - a) / steps
const xValues = []
for (let i = 0; i <= steps; i++) {
xValues.push(a + i * stepSize)
}
const xInfo = this.exchange.transferArrayToWASM(xValues, 'float')
try {
const result = this.module._trapezoidal_integral(
xInfo.ptr,
xInfo.length,
stepSize
)
return result
} finally {
this.exchange.free(xInfo.ptr)
}
}
// 线性回归分析
async linearRegression(xData, yData) {
await this.ensureInitialized()
const xInfo = this.exchange.transferArrayToWASM(xData, 'float')
const yInfo = this.exchange.transferArrayToWASM(yData, 'float')
try {
const resultPtr = this.module._linear_regression(
xInfo.ptr,
yInfo.ptr,
xInfo.length
)
const result = this.exchange.retrieveArrayFromWASM(resultPtr, 2, 'float')
return {
slope: result[0],
intercept: result[1],
}
} finally {
this.exchange.cleanup()
}
}
async ensureInitialized() {
if (!this.initialized) {
await this.initialize()
}
}
}性能监控与调试
WASM 性能分析工具
javascript
// lib/wasm-performance.js
import { performance, PerformanceObserver } from 'perf_hooks'
export class WASMPerformanceMonitor {
constructor() {
this.metrics = new Map()
this.observer = new PerformanceObserver((list) => {
this.processPerformanceEntries(list.getEntries())
})
this.startMonitoring()
}
startMonitoring() {
this.observer.observe({ entryTypes: ['measure', 'function'] })
}
// 包装 WASM 函数调用以进行性能监控
instrumentWASMFunction(moduleName, functionName, wasmFunction) {
return async (...args) => {
const startMark = `wasm-${moduleName}-${functionName}-start`
const endMark = `wasm-${moduleName}-${functionName}-end`
const measureName = `wasm-${moduleName}-${functionName}`
performance.mark(startMark)
try {
const result = await wasmFunction(...args)
performance.mark(endMark)
performance.measure(measureName, startMark, endMark)
this.recordSuccess(moduleName, functionName)
return result
} catch (error) {
performance.mark(endMark)
performance.measure(measureName, startMark, endMark)
this.recordError(moduleName, functionName, error)
throw error
}
}
}
processPerformanceEntries(entries) {
entries.forEach((entry) => {
if (entry.name.startsWith('wasm-')) {
const [_, moduleName, functionName] = entry.name.split('-')
if (!this.metrics.has(moduleName)) {
this.metrics.set(moduleName, new Map())
}
const moduleMetrics = this.metrics.get(moduleName)
if (!moduleMetrics.has(functionName)) {
moduleMetrics.set(functionName, {
callCount: 0,
totalTime: 0,
averageTime: 0,
minTime: Infinity,
maxTime: 0,
errorCount: 0,
successCount: 0,
})
}
const metrics = moduleMetrics.get(functionName)
metrics.callCount++
metrics.totalTime += entry.duration
metrics.averageTime = metrics.totalTime / metrics.callCount
metrics.minTime = Math.min(metrics.minTime, entry.duration)
metrics.maxTime = Math.max(metrics.maxTime, entry.duration)
}
})
}
recordSuccess(moduleName, functionName) {
this.updateMetrics(moduleName, functionName, 'success')
}
recordError(moduleName, functionName, error) {
this.updateMetrics(moduleName, functionName, 'error')
console.error(`WASM 函数调用错误 [${moduleName}.${functionName}]:`, error)
}
updateMetrics(moduleName, functionName, type) {
if (!this.metrics.has(moduleName)) {
this.metrics.set(moduleName, new Map())
}
const moduleMetrics = this.metrics.get(moduleName)
if (!moduleMetrics.has(functionName)) {
moduleMetrics.set(functionName, {
callCount: 0,
totalTime: 0,
averageTime: 0,
minTime: Infinity,
maxTime: 0,
errorCount: 0,
successCount: 0,
})
}
const metrics = moduleMetrics.get(functionName)
if (type === 'success') {
metrics.successCount++
} else if (type === 'error') {
metrics.errorCount++
}
}
// 生成性能报告
generatePerformanceReport() {
const report = {
timestamp: new Date().toISOString(),
modules: {},
}
for (const [moduleName, functions] of this.metrics) {
report.modules[moduleName] = {}
for (const [functionName, metrics] of functions) {
report.modules[moduleName][functionName] = {
...metrics,
successRate:
metrics.callCount > 0
? (metrics.successCount / metrics.callCount) * 100
: 0,
}
}
}
return report
}
// 识别性能瓶颈
identifyBottlenecks() {
const bottlenecks = []
const report = this.generatePerformanceReport()
for (const [moduleName, functions] of Object.entries(report.modules)) {
for (const [functionName, metrics] of Object.entries(functions)) {
if (metrics.averageTime > 100) {
// 超过 100ms 认为是瓶颈
bottlenecks.push({
module: moduleName,
function: functionName,
averageTime: metrics.averageTime,
callCount: metrics.callCount,
severity: metrics.averageTime > 500 ? 'HIGH' : 'MEDIUM',
})
}
}
}
return bottlenecks.sort((a, b) => b.averageTime - a.averageTime)
}
}
export const wasmPerformance = new WASMPerformanceMonitor()