TypeScript中的并发与并行编程:轻松搞定高效能应用
现代应用不仅需要高性能,还需要高响应性,需要开发人员掌握并发性和并行性。作为 JavaScript 超集的 TypeScript 提供了强大的工具和模式来管理这些复杂性。本指南从各个角度探讨了这两个概念,深入探讨了实用示例、模式和高级实践,以利用 TypeScript 中的并发性和并行性。
并发性 vs 并行性:主要区别是什么?在我们开始编码之前,理解这些术语非常重要:
1.并发:
- 定义: 系统通过轮流执行多个任务(而不是同时进行,而是依次进行)的能力。
- 示例: 在事件循环中,在处理数据库查询和文件上传任务之间交替进行。
2. 并列性:
- 定义:利用多核处理器同时做多个任务。
- 示例:比如,同时在不同的核心上进行复杂的数学运算。
可视化:
想象一下一家餐厅:
- 并发: 一个厨师同时忙好几个菜。
- 并行: 多个厨师同时做不同的菜。
JavaScript,以及由此延伸的TypeScript,运行在一个单线程事件循环中,这可能会让人误以为并发是不可能实现的。然而,可以通过回调、Promise、async/await等异步编程模型来实现并发。
1. 使用Promise来实现并发
Promise是实现TypeScript中异步编程最简单的方式之一。
const fetchData = (url: string) => {
return new Promise<string>((resolve) => {
setTimeout(() => resolve(`从${url}获取的数据`), 1000);
});
};
const main = async () => {
console.log('正在并发获取数据...');
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); // ["从https://api.example.com/1获取的数据", "从https://api.example.com/2获取的数据"]
};
main();
全屏模式 退出全屏
解释如下:
Promise.all
可以让两个 fetch 请求同时进行,节省时间成本。2. 用 async/await 实现并发async/await
简化了 promise 链式调用的过程,同时保持异步特性不变。
async function task1() {
console.log("任务1开始了");
await new Promise((resolve) => setTimeout(resolve, 2000));
console.log("任务1完成了");
}
async function task2() {
console.log("任务2开始了");
await new Promise((resolve) => setTimeout(resolve, 1000));
console.log("任务2完成了");
}
async function main() {
console.log("并发执行开始...");
console.log("等待所有任务完成:");
await Promise.all([task1(), task2()]);
console.log("所有任务都完成了");
}
main();
切换到全屏 切换退出全屏
TypeScript 中的并行编程尽管 JavaScript 本身不支持多线程,但 Web Workers 和 Node.js 的 Worker Threads 可以实现并行计算。这些特性利用单独的线程来处理计算密集的任务。
1. Web Workers 用于并行计算
在浏览器环境中,Web Workers 可以在一个独立的线程中运行脚本。
// worker.ts
// 监听消息事件
addEventListener('message', (event) => {
// 对接收到的数据进行处理,将每个数字乘以2
const result = event.data.map((num: number) => num * 2);
// 发送处理后的结果
postMessage(result);
});
全屏进入。退出全屏。
// main.ts
const worker = new Worker('worker.js');
worker.onmessage = (event) => {
console.log('工人发来的结果:', event.data);
};
worker.postMessage([1, 2, 3, 4]);
切换到全屏模式 退出全屏
2. Node.js 工作线程
Node.js 提供了 worker_threads
,用于处理多线程任务。
// worker.js
const { parentPort } = require('worker_threads');
// 这是一个用于处理消息的worker.js示例
parentPort.on('message', (data) => {
const result = data.map((num) => num * 2);
parentPort.postMessage(result);
});
切换到全屏 切换回正常模式
// main.js
const { Worker } = require('worker_threads');
const worker = new Worker('./worker.js');
worker.on('message', (result) => {
console.log('工作线程结果:', result);
});
worker.postMessage([1, 2, 3, 4]);
全屏 退出全屏
并行与并发编程的实用模式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();
}
}
// 示例用法
const queue = new TaskQueue(3);
for (let i = 0; i < 10; i++) {
queue.enqueue(async () => {
console.log(`任务 ${i} 正在开始`);
await new Promise((resolve) => setTimeout(resolve, 1000));
console.log(`任务 ${i} 已完成`);
});
}
进入全屏,退出全屏
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));
});
} else {
parentPort.on('message', (task) => {
parentPort.postMessage(task * 2);
});
}
进入全屏 退出全屏
挑战及应对措施1. 调试异步代码时遇到的问题
- 使用像
async_hooks
这样的工具在 Node.js 中追踪(跟踪)异步操作。 - 使用支持调试 async/await 代码的 IDEs。
2. 错误处理
- 用
try/catch
块包裹承诺,或者在Promise.all
后面加.catch()
。
3. 竞态条件
避免共享状态或使用锁机制来同步资源。
1. 优先使用异步 I/O: 避免在进行 I/O 密集型操作时阻塞主线程。
2. 使用 Worker 线程处理 CPU 密集型任务: 将计算密集型任务交给 worker 线程或 Web Workers。
3. 限制并发量: 使用任务队列或如 p-limit
之类的库来控制并发量。
4. 使用库: 使用 Bull
等任务队列库或 Workerpool
来管理 worker 线程。
结论部分
并发和并行对于构建高性能且可扩展的TypeScript应用至关重要。并发通过交错执行任务来提高响应性,而并行则可以在多核系统上同时执行任务。掌握这些概念,开发人员可以应对现代应用中的各种挑战,并提供流畅的用户体验。
你可以在这里找到我,我的个人主页是https://shafayet.zya.me
这是关闭Vim的方法哦...😭
如图所示,图片如下:
共同学习,写下你的评论
评论加载中...
作者其他优质文章