掌握 TypeScript 中的并发和并行

2025-06-07

掌握 TypeScript 中的并发和并行

现代应用程序追求高性能和高响应速度,这要求开发人员掌握并发和并行技术。TypeScript 作为 JavaScript 的超集,提供了强大的工具和模式来管理这些复杂性。本指南从各个角度探讨了这两个概念,深入探讨了在 TypeScript 中利用并发和并行技术的实际示例、模式和高级实践。

并发与并行:主要区别

在开始编写代码之前,理解以下术语至关重要:

1.并发:

  • 定义:系统通过交错执行(不一定同时执行)来处理多个任务的能力。
  • 示例:在事件循环中在处理数据库查询和处理文件上传之间切换。

2.并行性:

  • 定义:利用多核处理器同时执行多项任务。
  • 示例:同时在不同的核心上执行复杂的数学计算。

可视化:
想象一家餐厅:

  • 并发:一位厨师同时处理多道菜肴。
  • 并行性:多位厨师同时制作不同的菜肴。

TypeScript 中的并发

JavaScript,以及 TypeScript 的扩展,都在单线程事件循环上运行,这听起来似乎不可能实现并发。然而,并发是通过回调promiseasync/await等异步编程模型实现的。

1. 使用 Promises 实现并发
Promises 是在 TypeScript 中实现并发的最简单方法之一。

const fetchData = (url: string) => {
  return new Promise<string>((resolve) => {
    setTimeout(() => resolve(`Data from ${url}`), 1000);
  });
};

const main = async () => {
  console.log('Fetching data concurrently...');
  const data1 = fetchData('https://api.example.com/1');
  const data2 = fetchData('https://api.example.com/2');

  const results = await Promise.all([data1, data2]);
  console.log(results); // ["Data from https://api.example.com/1", "Data from https://api.example.com/2"]
};
main();
Enter fullscreen mode Exit fullscreen mode

解释:

  • Promise.all允许两个获取操作同时运行,从而节省时间。2 . 使用 Async/Await 的并发 async/await简化了承诺链,同时保持了异步特性。
async function task1() {
  console.log("Task 1 started");
  await new Promise((resolve) => setTimeout(resolve, 2000));
  console.log("Task 1 completed");
}

async function task2() {
  console.log("Task 2 started");
  await new Promise((resolve) => setTimeout(resolve, 1000));
  console.log("Task 2 completed");
}

async function main() {
  console.log("Concurrent execution...");
  await Promise.all([task1(), task2()]);
  console.log("All tasks completed");
}
main();
Enter fullscreen mode Exit fullscreen mode

TypeScript 中的并行性

虽然 JavaScript 本身不支持多线程,但 Web Workers 和 Node.js Worker Threads 可以实现并行。这些功能利用单独的线程来处理计算量大的任务。

1. Web Workers 的并行性
在浏览器环境中,Web Workers 在单独的线程中执行脚本。

// worker.ts
addEventListener('message', (event) => {
  const result = event.data.map((num: number) => num * 2);
  postMessage(result);
});
Enter fullscreen mode Exit fullscreen mode
// main.ts
const worker = new Worker('worker.js');

worker.onmessage = (event) => {
  console.log('Result from worker:', event.data);
};

worker.postMessage([1, 2, 3, 4]);
Enter fullscreen mode Exit fullscreen mode



2. Node.js 工作线程
对于服务器端应用程序,Node.js 提供了worker_threads

// worker.js
const { parentPort } = require('worker_threads');
parentPort.on('message', (data) => {
  const result = data.map((num) => num * 2);
  parentPort.postMessage(result);
});
Enter fullscreen mode Exit fullscreen mode
// main.js
const { Worker } = require('worker_threads');

const worker = new Worker('./worker.js');
worker.on('message', (result) => {
  console.log('Worker result:', result);
});
worker.postMessage([1, 2, 3, 4]);
Enter fullscreen mode Exit fullscreen mode

有效并发和并行的模式

1. 用于管理并发的任务队列
在处理许多任务时,任务队列可确保受控执行。

class TaskQueue {
  private queue: (() => Promise<void>)[] = [];
  private running = 0;
  constructor(private concurrencyLimit: number) {}

  enqueue(task: () => Promise<void>) {
    this.queue.push(task);
    this.run();
  }

  private async run() {
    if (this.running >= this.concurrencyLimit || this.queue.length === 0) return;

    this.running++;
    const task = this.queue.shift();
    if (task) await task();
    this.running--;
    this.run();
  }
}

// Usage
const queue = new TaskQueue(3);
for (let i = 0; i < 10; i++) {
  queue.enqueue(async () => {
    console.log(`Task ${i} started`);
    await new Promise((resolve) => setTimeout(resolve, 1000));
    console.log(`Task ${i} completed`);
  });
}
Enter fullscreen mode Exit fullscreen mode



2. 使用工作池进行负载平衡
工作池可以有效地在多个工作器之间分配任务。

import { Worker, isMainThread, parentPort, workerData } from 'worker_threads';

if (isMainThread) {
  const workers = Array.from({ length: 4 }, () => new Worker(__filename));
  const tasks = [10, 20, 30, 40];
  workers.forEach((worker, index) => {
    worker.postMessage(tasks[index]);
    worker.on('message', (result) => console.log('Result:', result));
  });
} else {
  parentPort.on('message', (task) => {
    parentPort.postMessage(task * 2);
  });
}
Enter fullscreen mode Exit fullscreen mode

挑战与解决方案

1. 调试异步代码

  • 使用 Node.js 之类的工具async_hooks来跟踪异步操作。
  • 使用支持调试异步/等待代码的 IDE。

2.错误处理

  • 将承诺包装在try/catch块中或use .catch()Promise.all

3. 竞争条件
避免共享状态或使用锁定机制。

并发和并行的最佳实践

1. 优先考虑异步 I/O:避免 I/O 密集型操作阻塞主线程。2
. 使用工作线程执行 CPU 密集型任务:将繁重的计算任务卸载到工作线程或 Web Worker 上。3
. 限制并发:使用任务队列或类似库p-limit来控制并发级别。4
. 利用库:使用类似库Bull进行任务队列或Workerpool工作线程管理。

结论:
并发性和并行性对于构建高性能、可扩展的 TypeScript 应用程序至关重要。并发性通过交错执行任务来提高响应速度,而并行性则支持在多核系统上同时执行。掌握这些概念,开发人员可以应对现代应用程序中的挑战,并提供无缝的用户体验。


我的个人网站:https://shafayet.zya.me


这是如何关闭 Vim...😭😭😭

图片描述

文章来源:https://dev.to/shafayeat/mastering-concurrency-and-parallelism-in-typescript-1bgf
PREV
掌握 JavaScript 事件委托
NEXT
根据用户系统设置将您的 Web 应用设置为暗/亮模式