0

我的问题基本上归结为“我如何让这段线程 Python 代码在我的 GPU 而不是我的 CPU 上运行?”

我正在开发一个类似于旅行推销员问题的程序,在该程序中我递归地检查每个可能的移动(当然还有优化)。棘手的是全局变量的保留——python 的本机线程在这方面做得很好,而我使用的算法完全依赖于全局变量——我知道,这很糟糕。冒着进入太多细节的风险,我的许多线程将不得不产生它们自己的单独线程,直到某个“深度”(我发现大约 3 个效果最好),此时每个线程将不再被并行化,并且函数将被线性执行。

一开始它工作得很好,然后我通过线程化了一些性能改进。然而,它仍然不够好——如果我可以维护全局变量,那么理论上这个程序可以完全并行化,因此我认为它可以在 GPU 上快速运行。

目前代码很乱,但这是用伪代码表达的一般思想:

int x

function f( depth ):         # THE RECURSIVE f( n ) TEMPLATE

   global x
   # do stuff with x

   if depth <= maxDepth then # if we're still below the max depth
                             #    then we'll thread the next round of recursion.

      for i = 0 to n         # this number will change each time

         call_in_thread( target = f,
                         args   = depth + 1
                         )   # obviously the arguments
                             # passed to each thread will be a little different,
                             # but that shouldn't be a problem

   else                      # if we're already past the max depth,
                             # then we won't bother parallelising,
                             #      as the overheads would outweigh the benefits

      for i = 0 to n         # 

         f( depth + 1 )      # THE SELF-RECURSIVE CALL

所以我的问题很简单——我可以(轻松地)从线程 python 程序转换为在我的 GPU 上运行的线程 python 程序,同时仍然保持全局变量的使用?我知道 Numba/NumbaPro 的存在,但它们是非常令人生畏的软件包,我不确定像我这样的程序将如何转化为该框架。

4

1 回答 1

-1

问:我能否(轻松地)从线程化 Python 程序转换为在我的 GPU 上运行的线程化 Python 程序,同时仍保持对全局变量的使用?

A:基本上都没有,越不容易:

这是为什么部分:

a)在上面的伪代码中正式描绘的递归是有缺陷的。它不控制自己的终止,而是发散到无穷大,累积所有每次通过分配的资源停留并等待递归最深的返回点,直到它开始释放任何此类等待资源分配,因为递归合并阶段“冒泡”回到初始调用者。

b) python线程(截至 2019 年第三季度)主要是零并发,因为GIL阻止了并发,并且 python 线程并发处理故意运行得更糟(由于添加了新的开销)然后是纯[SERIAL]流程流(使用一个例外:延迟屏蔽(隐藏外部或 I/O 相关的请求/响应延迟和传输延迟)可能受益于多线程慢任务分离到多个线程,其中等待时间的并发性是改进的源泉,如果与请求、等待时间和响应后处理的纯[SERIAL]排序相比,在它最终到达(或没有)之后)

c)泛型递归是一种纯[SERIAL]多层次(有时非常深,但绝不是无限)嵌套的形式,在 a 的“反向传播”期间延迟使用更深层次的尚未计算的值终值,一路回溯,通过递归的巩固阶段。虽然特定的机会是,使用递归形式进行自我表达的通用算法很难并行化,并行化效率较低(请参阅所有附加成本在阿姆达尔定律中的作用),wrt这样做的间接费用。再加上计算的“密度”在递归调用期间会下降,而资源需求会一直增长。计算机科学的规则在这方面非常清楚。玩这个完全交互式的动画影响分析,并尝试将p-slider[PARALLEL]处理的 -fraction 低于不现实的 100% 并行代码的任何地方,就好像具有零实例化附加成本一样,好像有零转移附加成本,就好像有零结果合并附加成本一样,这样至少可以“嗅到”现实生活中的大火。

d) NUMA 生态系统(N on - Uniform Memory A访问系统,通过代理(设备驱动程序)介导的访问外语(无论是 CUDA c 语言、OpenCL、基于 SoC/FPGA 的混合体,编译成静态 GPU 内核代码,转移到 GPU 卡的“内部”并“让”相当自主地在那里执行)托管在远程分布式硬件上,由于 GPU-s 是 ) 的一个示例,因此很难期望在调用发起子系统中具有所有属性、均匀可用和工作,状态/值变化的双向协调传播越少。使用global即使在同质的纯 Python 软件中,也强烈建议不要使用 Python 端的变量(已知情况除外)

e)蟒蛇脚本(python 解释器解释的程序),线程越少,不在 GPU 上运行。GPU 设备也有它们的代码执行单元,称为线程,但它们在主要不同的硬件(供应商特定的基于 SM 的设备)上执行,这些硬件表现出 SIMD 并行性,因此是自主操作的线程,其中每个都有一个执行不同的代码,甚至具有相同的代码但不同的(在 GPU 术语中是不同的)代码执行路径,SIMD 设备将浪费时间来调度 SIMD 可执行线程并让所有不连贯的 SIMD 线程等待它们(发散) 转,直到他们的指令(每个线程不同)将获得所有 SIMD“空闲”执行,如果块中没有其他 SIMD 线程具有完全相同的 SIMD 指令来执行。如果不同的线程必须在 ~ < 2 GHz SIMD 设备上等待到未来的某个时间,人们可以猜测到巨大的性能下降,其中 32 线程(warp)宽的 SIMD 设备可以从任何其他工作中解放出来,并且可以首先“私下”提供一个(发散的)SIMD 线程。是的,有 python 工具,使 python 程序能够准备另一个“嵌入式”代码块,然后将其转换,然后编译,然后通过 GPU 设备队列下载到结构并安排GPU 设备上的远程执行,但所有这些转换都是复杂的,以便使用外国设备处理器的机器代码将此类算法转换到外国设备计算设备上的高级概念在那里执行,

f) GPU 托管的内核代码确实对资源使用极为敏感,如果是递归的,则更敏感。任何类型的递归算法的递归深度(这里的算法是发散的,如 a) 项中所述)本身甚至可能导致正确公式化的递归代码直接无法在 GPU 设备内运行,这是正确的到固定且相当少量的高性能片上内存资源(与现代 CPU 上的大小相比,即使在 HPC 驱动的 GPU 结构上,SM 缓存的大小也非常有限,而不是谈论主流,主要面向游戏的 GPU 卡)。

于 2019-07-24T05:20:56.333 回答