Bootstrap

并发和并行的基础知识

1. 并发(Concurrency)的例子

场景:单核计算机同时运行多个应用程序

假设你正在使用一台单核 CPU 的计算机,你同时打开了以下任务:

  • 任务 A:听音乐(音乐播放器)。
  • 任务 B:编写文档(Word 文档)。
  • 任务 C:下载文件(浏览器)。

虽然只有一个 CPU 核心,这些任务似乎在“同时”进行,但实际上计算机通过快速切换任务来实现并发:

如何实现并发?

  1. 任务切片

    • CPU 分配时间片(如 10 毫秒)给每个任务。
    • 时间片到期后,切换到另一个任务。
  2. 任务调度

    • 操作系统(如 Windows 或 Linux)通过调度器管理任务的执行顺序。
    • 任务的切换对用户透明,用户感知不到切换过程。

具体流程:

  • 时间片 1:CPU 执行任务 A(播放音乐)。
  • 时间片 2:CPU 切换到任务 B(处理文档)。
  • 时间片 3:CPU 切换到任务 C(下载文件)。
  • 重复上述步骤。

尽管 CPU 在某一时刻只能执行一个任务,但因为切换速度极快(毫秒级),你会感觉这些任务在同时运行。


代码模拟:单线程并发任务

以下示例模拟单核 CPU 的任务切换:

public class ConcurrencyExample {
    public static void main(String[] args) {
        Runnable musicTask = () -> {
            for (int i = 0; i < 5; i++) {
                System.out.println("Playing music...");
                sleep(100);
            }
        };

        Runnable documentTask = () -> {
            for (int i = 0; i < 5; i++) {
                System.out.println("Editing document...");
                sleep(100);
            }
        };

        Runnable downloadTask = () -> {
            for (int i = 0; i < 5; i++) {
                System.out.println("Downloading file...");
                sleep(100);
            }
        };

        // 按顺序执行任务,模拟任务切换
        for (int i = 0; i < 5; i++) {
            musicTask.run();
            documentTask.run();
            downloadTask.run();
        }
    }

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

运行结果

Playing music...
Editing document...
Downloading file...
Playing music...
Editing document...
Downloading file...
...
  • 每个任务交替运行,给人感觉是“同时”执行的。
  • 本质上是通过快速切换来模拟并发。

2. 并行(Parallelism)的例子

场景:多核计算机同时运行多个任务

现在假设你使用一台四核 CPU的计算机,仍然执行以下任务:

  • 任务 A:听音乐(音乐播放器)。
  • 任务 B:编写文档(Word 文档)。
  • 任务 C:下载文件(浏览器)。
  • 任务 D:视频压缩(FFmpeg)。

在多核环境下,不同任务可以真正同时运行,每个任务分配到一个 CPU 核心:

如何实现并行?

  1. 多核 CPU 的任务分配

    • CPU 核心 1:执行任务 A(音乐播放器)。
    • CPU 核心 2:执行任务 B(文档编辑)。
    • CPU 核心 3:执行任务 C(文件下载)。
    • CPU 核心 4:执行任务 D(视频压缩)。
  2. 真正的同时运行

    • 多核系统中,每个核心可以独立处理任务。
    • 这些任务在物理上同时运行,不需要时间片轮转。

代码模拟:多线程并行任务

以下代码使用多线程模拟多核 CPU 的并行执行:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ParallelismExample {
    public static void main(String[] args) {
        // 创建一个线程池,模拟 4 核 CPU
        ExecutorService executor = Executors.newFixedThreadPool(4);

        // 定义四个任务
        executor.submit(() -> playMusic());
        executor.submit(() -> editDocument());
        executor.submit(() -> downloadFile());
        executor.submit(() -> compressVideo());

        executor.shutdown();
    }

    private static void playMusic() {
        for (int i = 0; i < 5; i++) {
            System.out.println("Playing music...");
            sleep(100);
        }
    }

    private static void editDocument() {
        for (int i = 0; i < 5; i++) {
            System.out.println("Editing document...");
            sleep(100);
        }
    }

    private static void downloadFile() {
        for (int i = 0; i < 5; i++) {
            System.out.println("Downloading file...");
            sleep(100);
        }
    }

    private static void compressVideo() {
        for (int i = 0; i < 5; i++) {
            System.out.println("Compressing video...");
            sleep(100);
        }
    }

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

运行结果(顺序可能不同):

Playing music...
Editing document...
Downloading file...
Compressing video...
Playing music...
Editing document...
Downloading file...
Compressing video...
...
  • 每个任务分配到不同的线程,线程在多核 CPU 上真正同时运行。
  • 输出顺序可能不同,取决于操作系统和线程调度器的工作方式。

3. 并发与并行的结合

场景:并发和并行的混合使用

假设:

  • 你有 4 核 CPU。
  • 运行 8 个任务(任务 A 到 H)。

操作系统会结合并发并行来调度任务:

  1. 并行
    • 4 个任务同时运行在 4 核 CPU 上。
  2. 并发
    • 当某个任务阻塞时(如 I/O 操作),CPU 切换到其他任务继续执行。
示意图
时间线: 核心 1   | A |   | B |   | A |   | B |
          核心 2   | C |   | D |   | C |   | D |
          核心 3   | E |   | F |   | E |   | F |
          核心 4   | G |   | H |   | G |   | H |

4. 实际应用场景

场景并发(Concurrency)并行(Parallelism)
浏览器加载网页同时处理多个请求(图片、视频、CSS 文件)在多核 CPU 上并行渲染页面、解码视频和执行脚本。
视频播放同时缓冲、解码和播放视频流(逻辑上的并发)。使用 GPU 解码并渲染视频帧(物理上的并行)。
编译代码同时编译多个模块(逻辑并发)。使用多核 CPU 同时编译多个模块(物理并行)。
AI 训练同时加载数据、更新参数(逻辑并发)。使用 GPU 同时训练多个神经网络或并行处理不同的数据批次。
操作系统任务调度多个任务共享 CPU 时间片,逻辑上的并发。多核 CPU 上任务真正同时运行。

5. 总结

  • 并发: 通过任务切换,多个任务在同一时间段内交替运行,强调任务管理和逻辑上的“同时进行”。
  • 并行: 依赖多核或分布式系统,多个任务在物理上真正同时运行,强调性能和效率提升。
;