TypeScript中的并发与多线程:从理论到实践
现代Web应用程序需要高性能。TypeScript运行在Node.js之上,提供了强大的工具来同时处理多个任务。本文将探讨TypeScript中并发与多线程的工作原理,并学习如何在实际中应用它们。
并发 vs 并行:关键区别
在深入代码之前,理解并发与并行之间的区别很重要。
- 并发 — 是程序通过切换任务来处理多个任务的能力。在JavaScript/TypeScript中,这是通过Event Loop和异步操作实现的。
- 并行 — 是在不同CPU核心上同时执行多个任务。在Node.js中,这是通过Worker Threads实现的。
TypeScript(和JavaScript一样)本质上是单线程的,但通过异步和Worker Threads,我们可以有效地使用这两种方法。
异步:TypeScript中并发的基础
异步编程是迈向并发的第一步。让我们看看主要机制。
Promises 和 async/await
现代TypeScript广泛使用async/await来处理异步操作。这允许编写看起来是同步的,但实际上是并发执行的代码。
// 异步函数示例async function fetchData(url: string): Promise<any> { const response = await fetch(url); return response.json();}
// 并发启动多个请求async function fetchAllData(): Promise<void> { const [users, posts, comments] = await Promise.all([ fetchData('/api/users'), fetchData('/api/posts'), fetchData('/api/comments') ]); console.log('所有数据已并发加载');}Promise.all允许同时启动多个异步操作,与顺序执行相比,这大大加快了执行速度。
异步代码中的错误处理
在并发执行中正确处理错误很重要:
async function safeFetchAll(): Promise<void> { try { const results = await Promise.allSettled([ fetchData('/api/users'), fetchData('/api/invalid'), fetchData('/api/posts') ]); results.forEach((result, index) => { if (result.status === 'fulfilled') { console.log(`请求 ${index} 成功:`, result.value); } else { console.error(`请求 ${index} 失败:`, result.reason); } }); } catch (error) { console.error('严重错误:', error); }}Worker Threads:TypeScript中的真正多线程
对于CPU密集型任务(图像处理、复杂计算),仅靠异步是不够的。这时Worker Threads就派上用场了——它们是真正的执行线程。
创建Worker Thread
让我们看一个在单独线程中计算斐波那契数列的例子:
// fibonacci.worker.tsimport { parentPort } from 'worker_threads';
function fibonacci(n: number): number { if (n <= 1) return n; return fibonacci(n - 1) + fibonacci(n - 2);}
parentPort?.on('message', (n: number) => { const result = fibonacci(n); parentPort?.postMessage(result);});// main.tsimport { Worker } from 'worker_threads';import path from 'path';
function runFibonacci(n: number): Promise<number> { return new Promise((resolve, reject) => { const worker = new Worker(path.resolve(__dirname, 'fibonacci.worker.ts')); worker.postMessage(n); worker.on('message', (result: number) => { resolve(result); worker.terminate(); }); worker.on('er