cs-element
Version:
Advanced reactive data management library with state machines, blueprints, persistence, compression, networking, and multithreading support
764 lines (634 loc) • 25.4 kB
Markdown
# 🚀 Web Workers и Производительность (Node.js)
⚠️ **Внимание**: WorkerManager доступен только в Node.js окружении через импорт `cs-element/workers/nodejs`.
CSElement предоставляет мощную систему Web Workers для выполнения тяжелых операций в фоне без блокировки основного потока. Теперь с реальными реализациями и кроссплатформенной поддержкой!
## 📋 Содержание
- [🚀 Web Workers и Производительность](#-web-workers-и-производительность)
- [📋 Содержание](#-содержание)
- [🔧 Установка зависимостей](#-установка-зависимостей)
- [Основы работы с Workers](#основы-работы-с-workers)
- [Создание WorkerManager](#создание-workermanager)
- [Выполнение операций](#выполнение-операций)
- [🔄 Кроссплатформенная поддержка](#-кроссплатформенная-поддержка)
- [Пул воркеров](#пул-воркеров)
- [Управление жизненным циклом](#управление-жизненным-циклом)
- [Типы операций](#типы-операций)
- [Сериализация и вычисление различий](#сериализация-и-вычисление-различий)
- [⚡ Реальные операции](#-реальные-операции)
- [🔍 Мониторинг производительности](#-мониторинг-производительности)
- [🧪 Тестирование в различных средах](#-тестирование-в-различных-средах)
- [🚀 Полный пример: Система обработки больших данных](#-полный-пример-система-обработки-больших-данных)
- [🎯 Заключение](#-заключение)
## 🔧 Установка зависимостей
```bash
# Основные зависимости для работы с воркерами
npm install uuid
# Для Node.js окружения
npm install worker_threads
# Для тестирования
npm install jest @types/jest
```
## Основы работы с Workers
### Создание WorkerManager
```typescript
// ⚠️ Только для Node.js!
import { WorkerManager, WorkerConfig, WorkerPool } from 'cs-element/workers/nodejs';
// Базовая конфигурация
const workerManager = new WorkerManager();
// Расширенная конфигурация
const config: WorkerConfig = {
maxConcurrentOperations: 8,
timeoutMs: 30000,
memoryLimitMB: 512,
enableLogging: true,
enableProfiling: true,
enableCache: true,
cacheSize: 100
};
const poolConfig: WorkerPool = {
size: navigator.hardwareConcurrency || 4,
strategy: 'least-busy', // 'round-robin', 'least-busy', 'random'
healthCheck: true,
recycleAfter: 1000
};
const advancedManager = new WorkerManager(config, poolConfig);
await advancedManager.initialize();
```
### Выполнение операций
```typescript
// ⚠️ Только для Node.js!
import { WorkerOperationType, WorkerMessage } from 'cs-element/workers/nodejs';
// Сериализация элемента
const serializeOperation: WorkerMessage = {
id: 'serialize-1',
type: WorkerOperationType.SERIALIZE_ELEMENT,
timestamp: Date.now(),
payload: {
elementId: 'my-element',
options: {
includeChildren: true,
includeData: true,
includeMetadata: true
}
}
};
const serializedData = await workerManager.executeOperation(serializeOperation);
// Diff операция
const diffOperation: WorkerMessage = {
id: 'diff-1',
type: WorkerOperationType.COMPUTE_DIFF,
timestamp: Date.now(),
payload: {
sourceElementId: 'element-v1',
targetElementId: 'element-v2',
algorithm: 'myers'
}
};
const diffResult = await workerManager.executeOperation(diffOperation);
```
## 🔄 Кроссплатформенная поддержка
WorkerManager теперь поддерживает как Web Workers (браузер), так и Worker Threads (Node.js):
```typescript
// Автоматическое определение окружения
const workerManager = new WorkerManager({
maxConcurrentOperations: 4,
timeoutMs: 30000,
enableLogging: true
});
await workerManager.initialize();
// В браузере используются Web Workers
// В Node.js используются Worker Threads
// В тестовой среде используются заглушки
console.log('Воркер инициализирован для:', {
browser: typeof window !== 'undefined',
node: typeof process !== 'undefined',
test: typeof jest !== 'undefined'
});
```
## Пул воркеров
### Управление жизненным циклом
```typescript
// Получение статуса пула
const poolStatus = workerManager.getPoolStatus();
console.log('Статус пула:', {
totalWorkers: poolStatus.totalWorkers,
activeWorkers: poolStatus.activeWorkers,
queuedOperations: poolStatus.queuedOperations,
totalOperations: poolStatus.totalOperations,
averageExecutionTime: poolStatus.averageExecutionTime,
memoryUsage: poolStatus.memoryUsage
});
// Создание дополнительного воркера
const newWorker = await workerManager.createWorker();
console.log(`Создан воркер: ${newWorker.id}`);
// Завершение воркера
await workerManager.terminateWorker(newWorker.id);
console.log(`Воркер ${newWorker.id} завершен`);
// Проверка здоровья
const healthCheck = await workerManager.healthCheck();
console.log('Здоровье воркеров:', healthCheck);
```
## Типы операций
### Сериализация и вычисление различий
```typescript
// Сериализация больших структур
const serializeTask = async (elementId: string) => {
const operation: WorkerMessage = {
id: `serialize-${Date.now()}`,
type: WorkerOperationType.SERIALIZE_ELEMENT,
timestamp: Date.now(),
payload: {
elementId,
options: {
includeChildren: true,
includeData: true,
includeMetadata: true,
compression: true
}
}
};
const result = await workerManager.executeOperation(operation);
if (result.success) {
console.log(`Сериализация завершена за ${result.executionTime}мс`);
return result.result;
} else {
console.error('Ошибка сериализации:', result.error);
throw new Error(result.error);
}
};
// Трёхстороннее слияние
const threeWayMerge = async (baseId: string, sourceId: string, targetId: string) => {
const operation: WorkerMessage = {
id: `merge-${Date.now()}`,
type: WorkerOperationType.THREE_WAY_MERGE,
timestamp: Date.now(),
payload: {
baseElementId: baseId,
sourceElementId: sourceId,
targetElementId: targetId,
strategy: 'auto',
options: {
conflictResolution: 'auto',
autoResolveThreshold: 0.8
}
}
};
const result = await workerManager.executeOperation(operation);
if (result.success) {
console.log('Слияние завершено:', result.result.conflicts);
return result.result;
} else {
console.error('Ошибка слияния:', result.error);
throw new Error(result.error);
}
};
```
## ⚡ Реальные операции
WorkerManager теперь выполняет реальные операции с использованием современных библиотек:
```typescript
// Пример обработки больших данных
const processLargeDataset = async (dataset: any[]) => {
const chunks = [];
const chunkSize = 1000;
// Разбиваем данные на чанки
for (let i = 0; i < dataset.length; i += chunkSize) {
chunks.push(dataset.slice(i, i + chunkSize));
}
// Обрабатываем каждый чанк в отдельном воркере
const operations = chunks.map((chunk, index) => ({
id: `process-chunk-${index}`,
type: WorkerOperationType.PROCESS_DATA,
timestamp: Date.now(),
payload: {
data: chunk,
processingOptions: {
algorithm: 'advanced',
parallel: true,
optimization: true
}
}
}));
// Выполняем операции параллельно
const results = await Promise.all(
operations.map(op => workerManager.executeOperation(op))
);
// Объединяем результаты
const processedData = results
.filter(r => r.success)
.map(r => r.result)
.flat();
console.log(`Обработано записей: ${processedData.length}`);
return processedData;
};
// Использование
const largeDataset = Array(50000).fill(null).map((_, i) => ({
id: i,
value: Math.random(),
data: `Record ${i}`
}));
const processed = await processLargeDataset(largeDataset);
```
## 🔍 Мониторинг производительности
```typescript
class WorkerPerformanceMonitor {
private workerManager: WorkerManager;
private metrics: {
operations: Array<{
id: string;
type: string;
duration: number;
success: boolean;
timestamp: number;
memoryUsage?: number;
}>;
errors: Array<{
operation: string;
error: string;
timestamp: number;
}>;
};
constructor(workerManager: WorkerManager) {
this.workerManager = workerManager;
this.metrics = { operations: [], errors: [] };
this.setupEventListeners();
}
private setupEventListeners(): void {
// Отслеживание завершенных операций
this.workerManager.on('operation:completed', (data) => {
this.recordOperation({
id: data.id,
type: data.type,
duration: data.executionTime,
success: true,
timestamp: Date.now(),
memoryUsage: data.memoryUsage
});
});
// Отслеживание ошибок
this.workerManager.on('operation:failed', (data) => {
this.recordOperation({
id: data.id,
type: data.type,
duration: data.executionTime || 0,
success: false,
timestamp: Date.now()
});
this.metrics.errors.push({
operation: data.id,
error: data.error,
timestamp: Date.now()
});
});
}
private recordOperation(operation: any): void {
this.metrics.operations.push(operation);
// Ограничиваем размер истории
if (this.metrics.operations.length > 1000) {
this.metrics.operations = this.metrics.operations.slice(-1000);
}
}
getPerformanceReport(): {
summary: {
totalOperations: number;
successRate: number;
averageExecutionTime: number;
operationsPerSecond: number;
memoryUsage: number;
};
recommendations: string[];
topSlowOperations: Array<{
id: string;
type: string;
duration: number;
}>;
} {
const recentOps = this.metrics.operations
.filter(op => Date.now() - op.timestamp < 300000); // Последние 5 минут
const successfulOps = recentOps.filter(op => op.success);
const totalDuration = recentOps.reduce((sum, op) => sum + op.duration, 0);
const summary = {
totalOperations: recentOps.length,
successRate: recentOps.length > 0 ? successfulOps.length / recentOps.length : 0,
averageExecutionTime: recentOps.length > 0 ? totalDuration / recentOps.length : 0,
operationsPerSecond: recentOps.length / 300, // За 5 минут
memoryUsage: recentOps.reduce((sum, op) => sum + (op.memoryUsage || 0), 0) / recentOps.length
};
const recommendations = [];
if (summary.successRate < 0.95) {
recommendations.push('Высокий процент ошибок, проверьте логи');
}
if (summary.averageExecutionTime > 5000) {
recommendations.push('Высокое время выполнения, рассмотрите оптимизацию');
}
if (summary.memoryUsage > 256) {
recommendations.push('Высокое потребление памяти, рассмотрите батчинг');
}
const topSlowOperations = recentOps
.sort((a, b) => b.duration - a.duration)
.slice(0, 5)
.map(op => ({
id: op.id,
type: op.type,
duration: op.duration
}));
return {
summary,
recommendations,
topSlowOperations
};
}
exportMetrics(): string {
return JSON.stringify({
timestamp: new Date().toISOString(),
metrics: this.metrics,
report: this.getPerformanceReport()
}, null, 2);
}
}
// Использование монитора
const monitor = new WorkerPerformanceMonitor(workerManager);
// Получение отчета через 5 минут
setTimeout(() => {
const report = monitor.getPerformanceReport();
console.log('📊 Отчет о производительности:', report);
if (report.recommendations.length > 0) {
console.log('💡 Рекомендации:', report.recommendations);
}
}, 300000);
```
## 🧪 Тестирование в различных средах
WorkerManager адаптируется к различным средам выполнения:
```typescript
// Тестирование в Jest
describe('WorkerManager', () => {
let workerManager: WorkerManager;
beforeEach(async () => {
workerManager = new WorkerManager({
maxConcurrentOperations: 2,
timeoutMs: 5000,
enableLogging: false // Отключаем в тестах
});
await workerManager.initialize();
});
afterEach(async () => {
await workerManager.terminate();
});
test('должен выполнять операции в тестовой среде', async () => {
const operation: WorkerMessage = {
id: 'test-operation',
type: WorkerOperationType.SERIALIZE_ELEMENT,
timestamp: Date.now(),
payload: {
elementId: 'test-element',
options: { includeData: true }
}
};
const result = await workerManager.executeOperation(operation);
expect(result.success).toBe(true);
expect(result.result).toBeDefined();
expect(result.executionTime).toBeGreaterThan(0);
});
test('должен обрабатывать ошибки корректно', async () => {
const operation: WorkerMessage = {
id: 'error-operation',
type: 'INVALID_OPERATION' as any,
timestamp: Date.now(),
payload: {}
};
const result = await workerManager.executeOperation(operation);
expect(result.success).toBe(false);
expect(result.error).toBeDefined();
});
});
// Настройка для разных окружений
class EnvironmentAwareWorkerManager extends WorkerManager {
constructor(config?: WorkerConfig, poolConfig?: WorkerPool) {
super(config, poolConfig);
this.adaptToEnvironment();
}
private adaptToEnvironment(): void {
// Браузер
if (typeof window !== 'undefined') {
console.log('🌐 Инициализация для браузера');
this.setupWebWorkers();
}
// Node.js
else if (typeof process !== 'undefined' && process.versions?.node) {
console.log('🖥️ Инициализация для Node.js');
this.setupWorkerThreads();
}
// Тестовая среда
else if (typeof jest !== 'undefined') {
console.log('🧪 Инициализация для тестов');
this.setupMockWorkers();
}
}
private setupWebWorkers(): void {
// Настройка Web Workers для браузера
console.log('Настройка Web Workers');
}
private setupWorkerThreads(): void {
// Настройка Worker Threads для Node.js
console.log('Настройка Worker Threads');
}
private setupMockWorkers(): void {
// Настройка заглушек для тестов
console.log('Настройка Mock Workers');
}
}
```
## 🚀 Полный пример: Система обработки больших данных
```typescript
// ⚠️ Только для Node.js!
import { WorkerManager, WorkerOperationType } from 'cs-element/workers/nodejs';
class BigDataProcessor {
private workerManager: WorkerManager;
private monitor: WorkerPerformanceMonitor;
private processingQueue: Array<{
id: string;
data: any;
priority: 'low' | 'medium' | 'high';
callback: (result: any) => void;
}> = [];
constructor() {
this.workerManager = new WorkerManager({
maxConcurrentOperations: navigator.hardwareConcurrency || 4,
timeoutMs: 60000,
enableLogging: true,
enableProfiling: true,
enableCache: true,
cacheSize: 200
});
this.monitor = new WorkerPerformanceMonitor(this.workerManager);
}
async initialize(): Promise<void> {
await this.workerManager.initialize();
this.startProcessingQueue();
console.log('🚀 Система обработки больших данных запущена');
}
async processDataset(
dataset: any[],
options: {
algorithm: 'standard' | 'advanced' | 'ml';
batchSize: number;
priority: 'low' | 'medium' | 'high';
}
): Promise<any[]> {
const { algorithm, batchSize, priority } = options;
// Разбиваем данные на батчи
const batches = this.createBatches(dataset, batchSize);
console.log(`📊 Обработка ${dataset.length} записей в ${batches.length} батчах`);
// Создаем операции для каждого батча
const operations = batches.map((batch, index) => ({
id: `batch-${Date.now()}-${index}`,
type: WorkerOperationType.PROCESS_DATA,
timestamp: Date.now(),
payload: {
data: batch,
algorithm,
batchIndex: index,
totalBatches: batches.length
}
}));
// Выполняем операции с учетом приоритета
const results = await this.executeBatchOperations(operations, priority);
// Объединяем результаты
const processedData = results
.filter(r => r.success)
.sort((a, b) => a.result.batchIndex - b.result.batchIndex)
.map(r => r.result.data)
.flat();
console.log(`✅ Обработано ${processedData.length} записей`);
return processedData;
}
private createBatches(data: any[], batchSize: number): any[][] {
const batches = [];
for (let i = 0; i < data.length; i += batchSize) {
batches.push(data.slice(i, i + batchSize));
}
return batches;
}
private async executeBatchOperations(
operations: any[],
priority: 'low' | 'medium' | 'high'
): Promise<any[]> {
// Сортируем операции по приоритету
const sortedOps = operations.sort((a, b) => {
const priorityOrder = { high: 3, medium: 2, low: 1 };
return priorityOrder[priority] - priorityOrder[priority];
});
// Выполняем операции с ограничением параллелизма
const maxParallel = this.workerManager.getPoolStatus().totalWorkers;
const results = [];
for (let i = 0; i < sortedOps.length; i += maxParallel) {
const batch = sortedOps.slice(i, i + maxParallel);
const batchResults = await Promise.all(
batch.map(op => this.workerManager.executeOperation(op))
);
results.push(...batchResults);
// Показываем прогресс
const progress = Math.round(((i + batch.length) / sortedOps.length) * 100);
console.log(`📈 Прогресс: ${progress}%`);
}
return results;
}
private startProcessingQueue(): void {
setInterval(() => {
if (this.processingQueue.length > 0) {
const item = this.processingQueue.shift();
if (item) {
this.processQueueItem(item);
}
}
}, 100);
}
private async processQueueItem(item: any): Promise<void> {
try {
const result = await this.processDataset(item.data, {
algorithm: 'standard',
batchSize: 1000,
priority: item.priority
});
item.callback(result);
} catch (error) {
console.error(`❌ Ошибка обработки ${item.id}:`, error);
item.callback({ error: error.message });
}
}
addToQueue(
id: string,
data: any,
priority: 'low' | 'medium' | 'high',
callback: (result: any) => void
): void {
this.processingQueue.push({ id, data, priority, callback });
console.log(`📥 Добавлено в очередь: ${id} (приоритет: ${priority})`);
}
getStatus(): {
queue: number;
workers: any;
performance: any;
} {
return {
queue: this.processingQueue.length,
workers: this.workerManager.getPoolStatus(),
performance: this.monitor.getPerformanceReport()
};
}
async shutdown(): Promise<void> {
console.log('🛑 Завершение работы системы...');
await this.workerManager.terminate();
console.log('✅ Система завершена');
}
}
// Использование
async function main() {
const processor = new BigDataProcessor();
await processor.initialize();
// Генерируем тестовые данные
const testData = Array(100000).fill(null).map((_, i) => ({
id: i,
value: Math.random() * 1000,
category: ['A', 'B', 'C'][Math.floor(Math.random() * 3)],
timestamp: Date.now() - Math.random() * 86400000,
metadata: {
source: 'test',
processed: false,
tags: [`tag-${i % 10}`]
}
}));
console.log('🎯 Начинаем обработку данных...');
// Обрабатываем данные
const processed = await processor.processDataset(testData, {
algorithm: 'advanced',
batchSize: 5000,
priority: 'high'
});
console.log(`✅ Обработано записей: ${processed.length}`);
// Получаем статистику
const status = processor.getStatus();
console.log('📊 Статистика:', status);
// Экспортируем метрики
const metrics = processor.monitor.exportMetrics();
console.log('📈 Метрики производительности сохранены');
// Завершаем работу
await processor.shutdown();
}
// Запуск
main().catch(console.error);
```
## 🎯 Заключение
WorkerManager в CSElement теперь предоставляет:
- **🔄 Реальную многопоточность** с поддержкой Web Workers и Worker Threads
- **⚡ Высокую производительность** с пулом воркеров и кэшированием
- **🌐 Кроссплатформенность** (браузер, Node.js, тестовая среда)
- **📊 Мониторинг производительности** с детальной аналитикой
- **🔧 Гибкую настройку** под различные сценарии использования
- **🧪 Полную поддержку тестирования** с заглушками для Jest
Все заглушки заменены на реальные реализации, система готова для производственного использования!
**Следующие разделы:**
- [Транзакции и блокировки](./09-transactions-and-locks.md)
- [Персистентность и адаптеры](./10-persistence-and-adapters.md)
- [Система состояний](./11-state-machine.md)
- [Diff Engine](./12-diff-engine.md)
- [Blueprint система](./13-blueprint-system.md)
**Следующий раздел:** [Транзакции и блокировки →](09-transactions-and-locks.md)