← 中文资源

简体中文版本

事件循环

事件循环通过反复取出就绪的回调或事件并在单线程上运行至完成来驱动异步工作。

阅读英文原文

概念定义

事件循环是一个单线程调度器,处理事件或回调的队列:等待 I/O 就绪,运行关联的处理函数直至完成,再回到队列。非阻塞 I/O 让一个线程服务大量连接,因为等待被委托给操作系统而不是占用一个线程。该模型是协作式的——任何阻塞的处理函数都会拖住整个循环。

为什么重要

线程昂贵,而多数服务端工作花在等待 I/O 而非计算上。通过不为每次等待专配一个线程,事件循环以远少的内存服务远多的连接。它还从构造上消除了大部分数据竞争,因为回调不并行运行。这正是 Node.js 与浏览器 JavaScript 能在单线程上达到高 I/O 并发的原因。

工程实践

绝不要阻塞循环:把 CPU 密集与同步文件访问卸载到工作线程或独立进程。理解阶段顺序——定时器、I/O 回调、微任务——因为它改变代码相对于 promise 完成的执行时机,并避免用冗长的回调链饿死循环。防范可能悄悄中断链条的未处理拒绝,并让回调体保持简短以约束延迟。

代码示例

import java.util.concurrent.*;
import java.util.List;

public class CompletableFutureExample {

    static CompletableFuture<String> fetchUserName(int id) {
        return CompletableFuture.supplyAsync(() -> {
            sleep(200);
            return "User" + id;
        });
    }

    static CompletableFuture<Integer> fetchUserScore(String name) {
        return CompletableFuture.supplyAsync(() -> {
            sleep(300);
            return name.length() * 10;
        });
    }

    static void sleep(int ms) {
        try { Thread.sleep(ms); } catch (InterruptedException e) {}
    }

    public static void main(String[] args) throws Exception {
        CompletableFuture<String> pipeline = fetchUserName(42)
            .thenCompose(CompletableFutureExample::fetchUserScore)
            .thenApply(score -> "Score: " + score)
            .exceptionally(ex -> "Error: " + ex.getMessage());

        System.out.println(pipeline.get());

        CompletableFuture<String> f1 = CompletableFuture.supplyAsync(() -> "Hello");
        CompletableFuture<String> f2 = CompletableFuture.supplyAsync(() -> "World");

        String combined = f1.thenCombine(f2, (a, b) -> a + " " + b).get();
        System.out.println("Combined: " + combined);

        List<CompletableFuture<String>> futures = List.of(
            CompletableFuture.supplyAsync(() -> "Task1"),
            CompletableFuture.supplyAsync(() -> "Task2"),
            CompletableFuture.supplyAsync(() -> "Task3")
        );

        CompletableFuture<Void> all = CompletableFuture.allOf(
            futures.toArray(new CompletableFuture[0])
        );
        all.thenRun(() -> System.out.println("All tasks done")).get();
    }
}
export class Semaphore {
  constructor(limit) {
    if (!Number.isInteger(limit) || limit <= 0) throw new RangeError('limit must be a positive integer');
    this.limit = limit;
    this.active = 0;
    this.waiters = [];
  }

  async acquire() {
    if (this.active < this.limit) {
      this.active += 1;
      return () => this.release();
    }
    await new Promise((resolve) => this.waiters.push(resolve));
    this.active += 1;
    return () => this.release();
  }

  release() {
    if (this.active === 0) throw new Error('release without acquire');
    this.active -= 1;
    const next = this.waiters.shift();
    if (next) {
      this.active += 1;
      next(() => this.release());
    }
  }

  async run(task) {
    const release = await this.acquire();
    try {
      return await task();
    } finally {
      release();
    }
  }
}