并发(Concurrency)
定义:并发是指在同一个时间段内,多个任务(或线程)在系统中交替执行。并发任务并不是同时运行,而是通过共享资源来交替执行。现代操作系统通过时间片轮转(time slicing)和上下文切换(context switching)来实现并发。
关键点
-
上下文切换:操作系统将CPU从一个任务切换到另一个任务。这包括保存当前任务的状态(如寄存器值、程序计数器等),然后恢复即将执行任务的状态。
-
时间片轮转:操作系统把CPU时间划分成小段称为时间片,并将每个时间片分配给不同的任务,从而实现任务交替执行。
-
多线程(Multithreading):同一进程内的多个线程可以并发执行。每个线程有自己的堆栈和程序计数器,但共享同一进程的资源(如内存空间)。
示例
#include <iostream>
#include <thread>
#include <chrono>
// 任务1
void task1() {
for (int i = 0; i < 5; ++i) {
std::cout << "Task 1 - iteration " << i << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(1));
}
}
// 任务2
void task2() {
for (int i = 0; i < 5; ++i) {
std::cout << "Task 2 - iteration " << i << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(1));
}
}
int main() {
// 创建两个线程
std::thread t1(task1);
std::thread t2(task2);
// 等待线程完成
t1.join();
t2.join();
return 0;
}
在这个例子中,task1
和 task2
是两个并发执行的任务,通过 C++ 的多线程库 thread
来实现。
并行(Parallelism)
定义:并行是指在同一个时刻,多个任务在不同的处理器或处理器核心上同时运行。并行可以显著提高系统处理能力,因为多个任务真正地同时运行。
关键点
-
多核处理器:现代处理器通常具有多个核心,每个核心可以独立地执行任务。
-
多处理器系统:一个计算机系统中可能有多个处理器,每个处理器有自己的核心和缓存。
-
并行编程模型:包括使用多线程(如上文示例)和多进程。例如,C++ 中的
pthread
库或标准库的thread
可以用于并行执行。
示例
#include <iostream>
#include <thread>
#include <chrono>
#include <vector>
// 计算密集型任务
void computeTask(int id, int n) {
long long sum = 0;
for (int i = 0; i < n; ++i) {
sum += i;
}
std::cout << "Task " << id << " - completed with sum " << sum << std::endl;
}
int main() {
const int numTasks = 4;
const int numIterations = 100000000;
// 创建多个线程进行并行计算
std::vector<std::thread> threads;
for (int i = 0; i < numTasks; ++i) {
threads.emplace_back(computeTask, i, numIterations);
}
// 等待所有线程完成
for (auto& thread : threads) {
thread.join();
}
return 0;
}
在这个例子中,computeTask
是一个计算密集型任务,被分配到多个线程上并行执行。每个线程在不同的处理器核心上运行,从而实现真正的并行。
并发 vs 并行
-
并发:
- 并发可以在单处理器的系统上通过快速上下文切换交替利用处理器时间来实现。
- 适用于任务之间存在大量交互或共享资源的场景。
-
并行:
- 并行需要多处理器或多核心系统,通过硬件并行性来真正同时执行多个任务。
- 适用于计算密集型任务和彼此独立的任务。
如何使用并发和并行
选择使用并发还是并行,通常取决于任务的性质和系统的硬件资源。
- I/O 密集型任务:如文件读取、网络请求等,通常适合并发执行,因为这些任务大部分时间在等待 I/O 操作完成。在等待期间可以进行上下文切换去执行其他任务。
- 计算密集型任务:如大规模数据处理、科学计算等,通常适合并行执行,因为这些任务需要大量 CPU 资源,可以通过多个核心同时工作来减少总运行时间。