CLASS 18 · 2026-04-15 · 17-19 系统与界面

消息传递与网络

消息传递让并发模块通过发送不可变消息来交互,避免了共享可变数据的同步难题。把它从进程内 Worker 延伸到网络上的客户端/服务器,就构成了现代 Web 应用的骨架。

两种并发模型

消息传递并不能让并发变得「没有 bug」,但它把同步的复杂度集中到了消息边界上,更容易推理。

Worker 之间的消息传递

TypeScript(Node.js)用 worker_threads 提供工作线程。主线程与 Worker 通过 postMessage 发送消息,通过 parentPort.on('message', callback) 接收消息。

// 主线程
import { Worker } from 'worker_threads';
const worker = new Worker('./worker.js');
worker.postMessage({ type: 'add', a: 2, b: 3 });
worker.on('message', (result) => console.log(result)); // 5

// worker.js
import { parentPort } from 'worker_threads';
parentPort!.on('message', (msg) => {
  if (msg.type === 'add') parentPort!.postMessage(msg.a + msg.b);
});

消息类型

不同种类的消息通常用可辨识联合(discriminated union)表达,以一个 type 字段区分:

type Msg =
  | { type: 'add'; a: number; b: number }
  | { type: 'sub'; a: number; b: number }
  | { type: 'result'; value: number };

接收消息

Worker 通过事件监听器接收消息。parentPort.on('message', callback) 注册一个异步回调,每当有新消息到达时调用。

停止工作线程

如何优雅地让 Worker 停下来?常用手法是发送一条特殊的毒丸消息(poison pill)。Worker 收到毒丸后,清理资源并退出。

// 主线程发送毒丸
worker.postMessage({ type: 'stop' });

// Worker 处理毒丸
parentPort!.on('message', (msg) => {
  if (msg.type === 'stop') process.exit(0);
});

消息传递下的竞态条件

消息传递并不能消除竞态条件。如果两个客户端同时向服务器请求同一资源,服务器处理消息的顺序仍然会影响结果。只是这类竞态更容易被观察和控制。

客户端/服务器模式

客户端/服务器(client/server):客户端发送请求,服务器处理请求并返回响应。这是网络通信的基本设计模式。

网络基础

Web API

HTTP 是万维网的语言。一个 HTTP 请求包含:

TypeScript 中的 Web 服务器

用 Express 可以快速创建路由:

import express from 'express';
const app = express();

app.get('/api/users/:id', (req, res) => {
  const id = Number(req.params.id);
  res.json({ id, name: 'Ada' });
});

app.listen(3000, () => console.log('服务器启动于 3000 端口'));

关键要点

  • 模型消息传递用不可变消息交互,避免共享可变数据的同步。
  • WorkerpostMessage 发送,parentPort.on 接收,用可辨识联合区分消息。
  • 毒丸poison pill 消息用于优雅停止 Worker。
  • C/S客户端/服务器是网络交互的基本模式。
  • 网络IP + 主机名 + 端口定位进程,HTTP 定义请求/响应格式。