multithreading - GPGPU 与多核?

标签 multithreading performance multicore gpgpu parallel-processing

从程序员的角度来看,GPGPU 和常规多核/多线程 CPU 编程之间的主要实际区别是什么?具体来说:

  • 哪些类型的问题更适合常规多核,哪些类型更适合 GPGPU?
  • 编程模型的主要区别是什么?
  • 导致编程模型存在差异的关键底层硬件差异是什么?
  • 哪一个通常更容易使用以及使用多少?
  • 从长远来看,为 GPU 实现高级并行库(例如 Microsoft's task parallel library)是否可行?或 D's std.parallelism ?
  • 如果 GPU 计算效率如此惊人,为什么 CPU 的设计不更像 GPU?
  • 最佳答案

    有趣的问题。我已经研究过这个问题,所以我的回答是基于一些引用资料和个人经验。

    哪些类型的问题更适合常规多核,哪些类型更适合 GPGPU?

    就像提到的@Jared。 GPGPU 是为非常规则的吞吐量工作负载而构建的,例如图形、密集矩阵-矩阵乘法、简单的 photoshop 过滤器等。它们擅长容忍长延迟,因为它们天生就被设计为容忍纹理采样,一个 1000 多个周期的操作。 GPU 内核有很多线程:当一个线程触发长延迟操作(比如内存访问)时,该线程将进入休眠状态(而其他线程继续工作),直到长延迟操作完成。这允许 GPU 保持其执行单元比传统内核更忙。

    GPU 不擅长处理分支,因为 GPU 喜欢将“线程”(如果您不是 nVidia,则为 SIMD channel )批处理并一起发送到管道中以节省指令获取/解码能力。如果线程遇到分支,它们可能会发散,例如,8 线程经线中的 2 个线程可能会占用该分支,而其他 6 个线程可能不会占用它。现在,warp 必须分成大小为 2 和 6 的两个 warp。如果您的核心有 8 个 SIMD channel (这就是原始 warp 包含 8 个线程的原因),那么现在您的两个新形成的 warp 将运行效率低下。 2-thread warp 将以 25% 的效率运行,6-thread warp 将以 75% 的效率运行。可以想象,如果一个 GPU 继续遇到嵌套分支,它的效率会变得非常低。因此,GPU 不擅长处理分支,因此不应在 GPU 上运行带有分支的代码。

    GPU 的协作线程也很糟糕。如果线程需要相互通信,那么 GPU 将无法正常工作,因为 GPU 不支持同步(但 nVidia 支持同步)。

    因此,GPU 最糟糕的代码是并行度较低的代码或具有大量分支或同步的代码。

    编程模型的主要区别是什么?

    GPU 不支持中断和异常。对我来说,这就是最大的不同。除此之外,CUDA 与 C 没有太大区别。您可以编写一个 CUDA 程序,将代码发送到 GPU 并在那里运行。您在 CUDA 中访问内存的方式略有不同,但这同样不是我们讨论的基础。

    导致编程模型存在差异的关键底层硬件差异是什么?

    我已经提到过他们了。最大的是 GPU 的 SIMD 特性,它需要以非常规则的方式编写代码,没有分支和线程间通信。这是为什么,例如,CUDA 限制代码中嵌套分支的数量的部分原因。

    哪一个通常更容易使用以及使用多少?

    取决于您正在编码什么以及您的目标是什么。

    易于矢量化的代码:CPU 更易于编码,但性能较低。 GPU 编码稍难,但物有所值。
    对于所有其他人,CPU 更容易,而且性能通常也更好。

    从长远来看,为 GPU 实现高级并行库(例如 Microsoft 的任务并行库或 D 的 std.parallelism)是否可行?

    根据定义,任务并行需要线程通信并且也有分支。任务的思想是不同的线程做不同的事情。 GPU 是为许多做相同事情的线程而设计的。我不会为 GPU 构建任务并行库。

    如果 GPU 计算效率如此惊人,为什么 CPU 的设计不更像 GPU?

    世界上的许多问题都是分支和不规则的。上千个例子。图形搜索算法、操作系统、Web 浏览器等。只是补充一下——即使图形也像每一代一样变得越来越分支和通用,因此 GPU 将变得越来越像 CPU。我并不是说它们会变得像 CPU 一样,但它们会变得更加可编程。正确的模型介于低效 CPU 和非常专业的 GPU 之间。

    关于multithreading - GPGPU 与多核?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5919172/

    相关文章:

    multithreading - 使用 channel 在线程之间传递 Rust pnet 数据包

    java - 禁用所有中断

    java:线程ID重用ID

    java - java中如何启动ThreadGroup?

    mysql - 针对特定极慢查询的优化

    c++ - 使用 C++ 设置进程核心配额

    ESP32 的 Core 1 和 0 不能单独工作

    performance - 为什么在实践中使用快速排序?

    MYSQL SELECT 查询非常慢 - 可以使用 JOIN 吗?

    multithreading - 在两个内核上运行一个线程