# Python 与 Java 高并发处理示例

这个目录包含两个高并发处理示例，重点都不是 CPU 密集计算，而是大量 I/O 型任务的并发调度、限流和统计。

## Python 示例

文件：`python/asyncio_high_concurrency.py`

### 运行方式

在 `high-concurrency-demo` 目录下执行：

```bash
python python/asyncio_high_concurrency.py
```

运行后会输出总请求数、最大并发数、成功数、失败数、总耗时、吞吐量、平均延迟和最大延迟。

### 并发处理代码段

```python
async def handle_request(request_id: int, limiter: asyncio.Semaphore) -> Result:
    async with limiter:
        return await call_downstream(request_id)


async def main() -> None:
    limiter = asyncio.Semaphore(MAX_CONCURRENCY)
    tasks = [
        asyncio.create_task(handle_request(i, limiter))
        for i in range(1, TOTAL_REQUESTS + 1)
    ]
    results = await asyncio.gather(*tasks)
```

### 原理

- 使用 `asyncio` 创建大量协程任务。
- 使用 `asyncio.Semaphore` 控制同时执行的任务数量，避免把数据库、HTTP 服务或消息队列打满。
- 使用 `asyncio.gather` 等待所有任务完成，并统计吞吐量、平均耗时和失败数。
- 协程在遇到 `await asyncio.sleep(...)` 这类 I/O 等待时会主动让出执行权，事件循环可以继续调度其他任务。
- `Semaphore` 的值就是真实并发上限，示例中是 `MAX_CONCURRENCY = 100`，即最多 100 个任务同时访问下游。

### 执行过程

- 程序创建 `1000` 个协程任务，但任务不会全部同时进入下游调用。
- 每个任务先进入 `handle_request`，尝试获取 `Semaphore`。
- 拿到许可的任务执行 `call_downstream`，模拟一次 I/O 请求。
- 没拿到许可的任务挂起等待，不会阻塞整个线程。
- 单个任务完成后释放许可，等待中的下一个任务继续执行。
- 所有任务完成后，程序汇总成功数、失败数、吞吐量和延迟指标。

### 重点

- `asyncio` 适合 I/O 密集型高并发，例如 HTTP 调用、Redis、数据库访问、文件和队列操作。
- 不要无限制创建真实下游请求，必须用信号量、连接池或队列做背压。
- CPU 密集型任务不要只靠协程，应该用多进程、原生扩展或任务队列分摊。

## Java 示例

文件：`java/HighConcurrencyDemo.java`

### 运行方式

在 `high-concurrency-demo` 目录下执行：

```bash
javac java/HighConcurrencyDemo.java
java -cp java HighConcurrencyDemo
```

运行后会输出总请求数、最大并发数、成功数、失败数、总耗时、吞吐量、平均延迟和最大延迟。

### 并发处理代码段

```java
ThreadPoolExecutor executor = new ThreadPoolExecutor(
        MAX_CONCURRENCY,
        MAX_CONCURRENCY,
        30,
        TimeUnit.SECONDS,
        new LinkedBlockingQueue<>(QUEUE_CAPACITY),
        new ThreadPoolExecutor.CallerRunsPolicy()
);

List<Future<Result>> futures = new ArrayList<>(TOTAL_REQUESTS);

for (int i = 1; i <= TOTAL_REQUESTS; i++) {
    final int requestId = i;
    futures.add(executor.submit(() -> callDownstream(requestId)));
}

for (Future<Result> future : futures) {
    Result result = future.get();
    // collect metrics
}
```

### 原理

- 使用 Java 17 兼容的 `ThreadPoolExecutor` 承载大量阻塞式任务。
- 固定线程数控制真实并发量，有界队列控制堆积量，保护下游资源。
- 使用 `Future` 收集结果，并统计吞吐量、平均耗时和失败数。
- `MAX_CONCURRENCY` 同时作为核心线程数和最大线程数，示例中最多同时运行 `500` 个任务。
- `LinkedBlockingQueue<>(QUEUE_CAPACITY)` 是有界等待队列，避免提交速度过快导致内存无限增长。
- `CallerRunsPolicy` 会在队列满时让提交任务的主线程自己执行任务，从而降低继续提交的速度，形成背压。

### 执行过程

- 程序创建固定大小线程池，最大工作线程数为 `500`。
- 主线程循环提交 `10000` 个任务到线程池。
- 线程池中空闲线程会立即执行任务，忙不过来的任务进入有界队列等待。
- 如果线程和队列都满了，`CallerRunsPolicy` 会让主线程执行当前任务，提交速度自然下降。
- 每个任务通过 `Thread.sleep(...)` 模拟一次阻塞 I/O 调用。
- 主线程通过 `Future.get()` 等待所有任务完成，并汇总吞吐量和延迟指标。

### 重点

- 固定线程池适合 Java 17 及更早版本，适合演示传统阻塞 I/O 的高并发处理。
- `CallerRunsPolicy` 会在队列满时让提交任务的线程自己执行任务，形成简单背压。
- 生产环境还需要补充超时、重试、熔断、队列削峰、监控指标和优雅关闭。

## 两个示例的共同思路

- 任务数量可以很大，但真实并发必须受控。
- 高并发处理的核心是限流、背压、超时、资源池和可观测性。
- 吞吐量不是唯一指标，还要关注平均延迟、最大延迟、失败率和下游承载能力。
