Parallelität und Multithreading in TypeScript: Fortgeschrittenes Niveau

Online Python-Trainer für Anfänger

Lernen Sie Python einfach ohne theoretische Überlastung. Lösen Sie praktische Aufgaben mit automatischer Überprüfung und schreiben Sie Code direkt im Browser.

Kurs starten

Parallelität und Multithreading in TypeScript: Fortgeschrittenes Niveau



In der modernen Webentwicklung und bei serverseitigen Anwendungen in TypeScript wird die Fähigkeit, effektiv mit Parallelität und Multithreading zu arbeiten, zunehmend kritisch. Obwohl JavaScript eine single-threaded Sprache ist, bietet die Laufzeitumgebung (Browser oder Node.js) leistungsstarke Werkzeuge für die parallele Ausführung von Aufgaben. In diesem Artikel betrachten wir fortgeschrittene Techniken für die Arbeit mit Parallelität in TypeScript, einschließlich Worker Threads, SharedArrayBuffer, Atomics und Synchronisationsmustern.



1. Grundlagen: Event Loop und async/await



Bevor wir uns in Multithreading vertiefen, ist es wichtig zu verstehen, wie der Event Loop in TypeScript funktioniert. Parallelität in einer single-threaded Umgebung wird durch nicht-blockierende Ein-/Ausgabe und asynchrone Operationen erreicht.



Betrachten wir ein Beispiel mit Promise.allSettled() für die parallele Ausführung mehrerer asynchroner Aufgaben mit Fehlerbehandlung:



interface TaskResult<T> {  status: 'fulfilled' | 'rejected';  value?: T;  reason?: Error;}

async function runConcurrentTasks<T>( tasks: Promise<T>[]): Promise<TaskResult<T>[]> { const results = await Promise.allSettled(tasks); return results.map(result => { if (result.status === 'fulfilled') { return { status: 'fulfilled', value: result.value }; } else { return { status: 'rejected', reason: result.reason }; } });}

// Verwendungconst task1 = fetchData('/api/users');const task2 = fetchData('/api/posts');const task3 = fetchData('/api/comments');

const results = await runConcurrentTasks([task1, task2, task3]);


2. Worker Threads in Node.js: Echte Multithreading



Für CPU-intensive Aufgaben (z. B. Bildverarbeitung, Kryptografie, komplexe Berechnungen) sind echte Threads erforderlich. In Node.js werden dafür Worker Threads verwendet.



Erstellen wir einen typisierten Worker mit TypeScript:



// worker.tsimport { parentPort, workerData } from 'worker_threads';

interface WorkerInput { data: number[]; operation: 'sum' | 'multiply';}

interface WorkerOutput { result: number; duration: number;}

if (parentPort) { const input: WorkerInput = workerData; const start = performance.now(); let result: number; if (input.operation === 'sum') { result = input.data.reduce((acc, val) => acc + val, 0); } else { result = input.data.reduce((acc, val) => acc * val, 1); } const output: WorkerOutput = { result, duration: performance.now() - start }; parentPort.postMessage(output);}


Jetzt erstellen wir einen Manager zur Steuerung mehrerer Worker:



// threadPool.tsimport { Worker } from 'worker_threads';import path from 'path';

class ThreadPool<TInput, TOutput> { private workers: Worker[] = []; private taskQueue: Array<{ input: TInput; resolve: (value: TOutput) => void; reject: (reason?: any) => void; }> = [];

constructor( private workerScript: string, private poolSize: number = 4 ) { this.initialize(); }

private initialize(): void { for (let i = 0; i < this.poolSize; i++) { const worker = new Worker(this.workerScript); worker.on('message', (result: TOutput) => { const task = this.taskQueue.shift(); if (task) { task.resolve(result); } worker.postMessage(this.taskQueue[0]?.input); });

worker.on('error', (error) => { const task = this.taskQueue.shift(); if (task) { task.reject(error); } });

this.workers.push(worker); } }

async execute(input: TInput): Promise<TOutput> { return new Promise((resolve, reject) => { this.ta

Blogs

Buchempfehlungen