Concurrence et multithreading en TypeScript : niveau avancé

Formateur Python en ligne pour débutants

Apprenez Python facilement sans surcharge théorique. Résolvez des tâches pratiques avec vérification automatique et écrivez du code directement dans le navigateur.

Start Course

Concurrence et multithreading en TypeScript : niveau avancé



Dans le développement web moderne et les applications serveur en TypeScript, la capacité à travailler efficacement avec la concurrence et le multithreading devient cruciale. Bien que JavaScript soit un langage monothread, l'environnement d'exécution (navigateur ou Node.js) fournit des outils puissants pour l'exécution parallèle de tâches. Dans cet article, nous explorerons les techniques avancées de gestion de la concurrence en TypeScript, notamment les Worker Threads, SharedArrayBuffer, Atomics et les modèles de synchronisation.



1. Fondamentaux : Event Loop et async/await



Avant de plonger dans le multithreading, il est important de comprendre comment fonctionne l'Event Loop en TypeScript. La concurrence dans un environnement monothread est obtenue grâce aux entrées/sorties non bloquantes et aux opérations asynchrones.



Considérons un exemple utilisant Promise.allSettled() pour l'exécution concurrente de plusieurs tâches asynchrones avec gestion des erreurs :



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 }; } });}

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

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


2. Worker Threads dans Node.js : véritable multithreading



Pour les tâches intensives en CPU (par exemple, traitement d'images, cryptographie, calculs complexes), des threads réels sont nécessaires. Dans Node.js, on utilise les Worker Threads pour cela.



Créons un Worker typé avec 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);}


Créons maintenant un gestionnaire pour contrôler plusieurs Workers :



// 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

Book Recommendations