并行处理简介

168 阅读9分钟

并行处理简介

前言

本文为《CUDA与TensorRT部署学习笔记》系列中并行处理与GPU体系架构篇。本文主要从串行处理与并行处理的区别、并行处理的概念、常见的并行处理维度进行学习记录。

Goal:理解并行处理的基本概念,理解SIMD,以及编程中常见的并行处理方式。

1 串行处理与并行处理的区别

1.1 Sequential processing(串行)

1.1.1 定义

串行是指任务按照顺序一个接一个地执行,每个任务的开始必须等到前一个任务结束。

1.1.2 必须串行的两种情况

(1)数据依赖(Data Dependency)

数据依赖指的是一个计算任务需要依赖于另一个计算任务的结果。如果一个任务的输出作为另一个任务的输入,那么它们之间存在数据依赖。

(2)分支程序(Branching)

分支程序是指在程序执行过程中基于某些条件选择不同的执行路径。这通常涉及条件语句(如 if-else 语句)。

备注:为什么以下必须串行?

(1)数据依赖(Data Dependency)

  • 顺序执行: 如果任务 A 的结果需要作为任务 B 的输入,那么在执行时,必须先执行 A,然后才能执行 B。这是因为 B 需要 A 的输出,如果并行执行,就无法确保 A 已经完成。
  • 避免竞态条件: 并行执行可能导致竞态条件,即两个任务同时访问共享的数据,而其中一个任务可能会在另一个任务完成之前修改数据,导致不确定的结果。

(2)分支程序(Branching)

  • 逻辑决策: 在分支程序中,不同的分支路径可能基于某些条件做出逻辑决策。如果并行执行,就需要同时执行所有分支,这可能导致不确定的执行结果。
  • 避免竞态条件: 并行执行不同的分支可能会导致竞态条件,因为分支可能会影响共享的状态或资源。

1.2 Parallel processing(并行)

1.2.1 定义

并行是指多个任务同时执行,彼此独立进行。在并行执行中,不同的任务可以在同一时刻进行,相互之间没有直接的依赖关系。

1.2.2 一般涉及到并行的环节

(1)Loop parallelization

比如:在图像处理/深度学习中很多地方都是用到了循环。

  • pre/post process (前处理后处理)

    • resize, crop, blur, bgr2rgb, rgb2gray, dbscan, findCounters
  • DNN中的卷积(convolution layer)以及全连接层(Fully connected layer)

(2)Image processing and DNN

比如:双线性插值、卷积层、全连接层等

备注

(1)不同编程语言的默认的ordering是不同的:

  • row major: C/C++/Objective-C, Pascal, C#
  • column major: Fortran, OpenGL, MATLAB, R, Julia

大白话理解
串行处理就像是一个人做事,他只能做一件事,直到他做完这件事才能开始做下一件事。这样,他的效率就比较低。
并行处理就像是多个人一起做事,每个人可以做一件不同的事。这样,他们的效率就会提高。

2 并行处理的概念

2.1 基本概念

  • 指令/代码块同时执行
  • 充分利用multi-core(多核)的特性,多个core一起去完成一个或多个任务。
  • 并行是指同时进行的意思。并行是指同时处理多个任务或数据的技术。

2.2 容易混淆几个概念

2.2.1 并行和并发

(1)并行(Parallelism)

  • 定义:并行是指两个或多个任务同时执行的能力。在并行计算中,多个处理单元同时执行多个任务,每个任务在独立的处理单元上执行,彼此之间互不干扰。

  • 例子:比如,一个计算机程序分解为多个子任务,这些子任务同时在多个处理器上执行。这可以显著提高程序的执行速度。

  • 比喻:可以将并行比喻为一条宽而大的高速公路,多个车辆(任务)可以同时行驶,互不影响。

(2)并发(Concurrency)

  • 定义:并发是指两个或多个任务在重叠的时间段内执行的能力。在并发计算中,多个任务在同一时间段内交替执行,可能会在时间轴上重叠,但并不一定同时执行。

  • 例子:多个任务在同一处理器上交替执行,每个任务都有一段时间片(时间段),它们的执行顺序可能是交织的。

  • 比喻: 可以将并发比喻为一条狭窄但繁忙的道路,多个车辆(任务)依次行驶,可能会发生交替的情况。

(3)总结区别

  • 关键区别:并行是真正的同时执行,而并发是在一段时间内交替执行。

  • 硬件需求:并行通常需要多个处理单元,如多核处理器或多台计算机;而并发可以在单个处理器上通过时间片轮转实现。

  • 性能提升:并行通常能够更显著地提高性能,因为多个任务可以同时执行;而并发的性能提升可能受限于处理器的性能和任务的切换开销。

  • 复杂性:并行通常涉及更复杂的编程和同步机制,因为需要处理多个任务之间的数据共享和同步;而并发相对简单,因为任务之间的交替通常通过时间片轮转来管理。

2.2.2 进程和线程

(1)进程

  • 定义: 进程是操作系统中的一个独立的执行单位,拥有独立的内存空间、文件句柄和系统资源。每个进程都有自己的地址空间,数据段、堆栈段等都是独立的。

  • 特点:进程之间相互独立,一个进程的崩溃不会影响其他进程的稳定性。

  • 创建和销毁:创建和销毁进程通常比较耗费资源,因为每个进程都有自己的资源和环境。

(2)线程

  • 定义:线程是进程中的一个执行单元,是进程的一个子集。线程共享进程的内存空间和资源,但拥有独立的执行流。一个进程可以包含多个线程。

  • 特点:线程之间共享进程的资源,因此线程的创建和上下文切换比进程要轻量级。线程的崩溃可能会影响整个进程的稳定性。

  • 优势:线程之间的通信更容易,因为它们共享相同的地址空间,而无需特殊的通信机制。

(3)进程和线程的关系

  • 包含关系:一个进程可以包含多个线程,但一个线程只能属于一个进程。

  • 资源共享:进程中的线程可以共享进程的资源,包括内存、文件、I/O等。

  • 独立性:线程之间是相对独立的,每个线程都有自己的执行序列。

(4)进程和线程的区别

特征进程线程
资源分配独立共享
执行单元独立并发
调度单位进程线程

(5)总结

进程的优势在于独立性和资源的隔离,劣势在于调度效率低。线程的优势在于调度效率高,劣势在于资源共享导致的竞争和冲突。

2.2.3 多核和加速比

(1)多核(Multi-core)

  • 定义:多核指的是在一个 CPU 芯片上集成多个独立的处理核心。这样的设计可以让计算机系统同时执行多个任务,每个核心独立执行指令,从而提高整体的处理能力。

  • 特点:多核处理器可以在同一时间执行多个线程或进程,从而实现并行计算。

  • 优势:相比单核处理器,多核处理器在处理多任务、多线程和并行计算时表现更为出色。

(2)加速比(Speedup)

  • 定义:加速比是衡量并行计算效果的指标,它表示在使用多个处理单元(如多核处理器)相对于使用一个处理单元时的性能提升倍数。

  • 计算:加速比(Speedup)可以用以下公式表示:
    Speedup=单核执行时间/多核执行时间

  • 例子:如果一个任务在单核处理器上花费了10秒,在四核处理器上花费了2秒,那么加速比为 10/2=5 倍。

(3)关系

  • 多核处理器的存在使得并行计算更为容易实现。通过将任务分配给不同的核心,可以同时处理多个子任务,从而加速整体计算过程。

  • 加速比是衡量多核处理器性能提升的一种方式。如果一个任务在多核处理器上能够以更短的时间完成,那么加速比将大于1,表示性能有所提升。

  • 然而,并不是所有任务都能够实现理想的线性加速比(意思是双核的加速不一定是单核的两倍。双核的有时加速比也会比四核的快)。有些任务可能存在限制,使得加速比达不到处理器核心数的线性倍数。这可能是因为任务之间存在依赖关系、通信开销或者其他因素。

3 常见的并行处理

3.1 研究并行处理的方向很多

  • 编译器自动化并行优化
    GCC, LLVM, TVM, ...
  • 针对For循环的并行优化
    tile, fuse, split, vectorization, ...
  • 计算图优化
    CFG, HTG, MTG, ...
  • 数据流
    Dataflow compiler
    Dataflow architecture
  • Polyhedral
    Polyhedral compiler
  • HPC
    High performance computing
    ...

3.2 重点方向

3.2.1 SIMD

SIMD(Single Instruction, Multiple Data) 是一种计算机处理器的并行计算架构,其中一条指令可以同时操作多个数据元素。这种架构主要用于加速对大规模数据集进行相同操作的任务。

在CUDA编程与TensorRT中,以及NVIDIA中的tensor core的设计理念中都存在着SIMD。

CUDA编程中是使用的是SIMT(Single Instruction Multiple Thread),跟SIMD很相像,是SIMD的高级版。

大白话理解

你有一篮子相同的水果需要洗,SIMD 就像是你有很多只手,一下子就能同时处理这一篮子水果。这样,一条指令就能告诉所有的手同时进行同样的操作,加速了整个洗水果的过程。这就是 SIMD,通过一条指令同时操作多个数据,提高了计算速度。

3.2 在模型部署中比较常见的方法

3.2.1 CPU上的并行处理

  • OpenMP
  • pthread
  • MPI
  • Halide

(应用场景:图像预处理/后处理,Multi-task模型)

3.2.2 GPU上的并行处理

  • CUDA programming

(应用场景:DNN优化)

3.2.3 做模型部署需要考虑的点

异构架构上时会有多种核,模型部署时,要考虑怎么在GPU上更快,考虑怎么与CPU进行通讯、DSP等等。会考虑得更多~!