关于Numba的线程实现的说明
由Numbaparallel目标执行的工作由Numba线程层执行。实际上,“线程层”是Numba内置库,可以执行所需的并发执行。在撰写本文时,有三个可用的线程层,每个线程层都通过不同的较低级别的host线程库实现。上thread线程和对于给定的应用/系统的thread线程的适当选择的更多信息可在发现 threading layer documentatio。
以下各节要关注的相关信息是,执行并行线程库中的parallel_for函数。此功能的工作是协调和执行并行任务。
本文引用的相关源文件是
• numba/np/ufunc/tbbpool.cpp
• numba/np/ufunc/omppool.cpp
• numba/np/ufunc/workqueue.c
这些文件分别包含TBB,OpenMP和工作队列线程池实现。每个函数都包含函数 set_num_threads(),get_num_threads()和和get_thread_id(),以及在各自的调度程序中用于线程屏蔽的相关逻辑。请注意,基本线程局部变量逻辑在这些文件中都是重复的,并且不在它们之间共享。
• numba/np/ufunc/parallel.py
该文件包含了Python和JIT兼容的封装器 set_num_threads(),get_num_threads()和get_thread_id(),以及代码加载上述库到Python和启动线程池。
• numba/parfors/parfor_lowering.py
该文件包含用于为并行后端生成代码的主要逻辑。在生成调度程序代码的代码中访问该线程掩码,并将其传递给相关的后端调度程序功能。
线程屏蔽
作为其设计的一部分,Numba绝不会在numba.np.ufunc.parallel._launch_threads() 运行首次并行执行时,最初启动的线程之外启动新线程。这是由于在实施线程屏蔽之前已在Numba中实现了线程。保留此限制是为了使设计简单,尽管将来可以删除它。因此,可以以编程方式设置线程数,但只能设置为小于或等于已启动的总数。这是通过“屏蔽”未使用的线程来完成的,从而使它们不起作用。例如,在16核计算机上,如果用户要调用set_num_threads,则Numba将始终存在16个线程,但是其中12个线程将处于空闲状态以进行并行计算。进一步调用 set_num_threads(16) ,导致这些相同的线程在以后的计算中起作用。
添加了线程掩码,使用户可以以编程方式更改在线程层中执行工作的线程数。事实证明,线程屏蔽难以实现,需要开发一种适合用户,易于推理且可以安全实现的编程模型,并在各个线程层上具有一致的行为。
编程模型
选择的编程模型与OpenMP中的模型相似。做出此选择的原因是,它对于许多用户来说是熟悉的,范围有限且简单。通过调用指定正在使用 set_num_threads的线程数,可以通过调用查询正在使用的线程数 get_num_threads。这两个函数与它们的OpenMP对应(与上述限制相同,即掩码必须小于或等于已启动的线程)。执行语义也与OpenMP相似,因为一旦启动并行区域,更改线程掩码不会对当前正在执行的区域产生影响,但会对随后执行的并行区域产生影响。
实施
除了对线程层库中已经存在的用户代码进行限制以外,对用户代码没有其它限制,需要仔细考虑线程掩码的设计。无法将“线程掩码”存储在全局值中,因为同时使用线程层,可能会导致值本身出现竞争形式。涉及具有这种全局价值的各种互斥量的众多设计,最终仅通过理想实验就打破了所有这些互斥量。最终发现,在某些OpenMP实现之后,“线程掩码”最好以a实现。这意味着每个执行Numba并行函数的线程,都将具有一个线程本地存储(TLS)插槽,其中包含在线程中调度线程thread localparallel_for时,要使用的线程掩码的值。
TLS使用一个线程掩模的上述概念是相对容易实现的, get_num_threads和set_num_threads简单地需要解决的TLS时隙在给定的线程层。这也意味着可以从运行时调用中得出并行区域的执行调度get_num_threads。这是通过众所周知的且相对容易实现的C 库函数注册模式,并将其包装在内部Numba来实现的。
除了满足原始的前期线程屏蔽要求之外,还需要考虑以下一些更复杂的方案。
嵌套并行
在所有线程层中,“主线程”将调用该parallel_for 函数,然后在并行区域中,根据线程层的不同,一些其它线程将有助于完成实际工作。如果工作包含对另一个并行函数的调用(即嵌套并行性),则使调用的线程必须知道主线程的“线程掩码”是什么,以便可以将其传递到主线程中。 parallel_for在执行嵌套并行函数时调用。此行为的实现是特定于线程层的,但一般原则是“主线程”始终将线程掩码的值从其TLS插槽“发送”到线程层中,在并行区域中处于活动状态的所有线程。这些活动线程将在执行任何工作之前,使用此值更新其TLS插槽。该实现细节的最终结果是:
• 线程掩码正确传递到嵌套函数中
• 并行区域中的每个线程仍然可以安全地使用不同的掩码来调用嵌套函数,如果未明确设置,则使用从“主线程”继承的掩码
• parallel_for成功容纳具有动态调度,且线程可能在执行期间加入和离开活动池的线程层
• 任何“主线程”线程掩码都与活动线程池中线程的线程掩码的流入特性完全分离
Python线程独立调用并行函数
严格保护线程层启动顺序,确保启动既是线程安全的,又是进程安全的,并且每个进程运行一次。在具有大量threading都使用Numba的Python模块线程的系统中,启动序列中的第一个线程将正确设置其线程掩码,但是没有其他线程可以运行启动序列。这意味着其它线程将需要以其它方式设置其初始线程掩码。这是在get_num_threads调用,且不存在线程掩码时实现的,在这种情况下,线程掩码将设置为默认值。在该实现中,“不存在线程掩码”由值表示,-1。“默认线程掩码”(未设置)由值表示0。执行set_num_threads(NUMBA_NUM_THREADS),此算子也会立即调用,因此如果有-1或0,由于遇到此结果get_num_threads(),而表示上述过程中存在错误。
操作系统fork()调用
使用TLS也是在由Linux(用于Numba使用最流行的平台)驱动,将TLS传输到子进程fork(2, 3P)clone(2)CLONE_SETTLS。
线程ID
私有get_thread_id()函数被添加到每个线程后端,该函数为每个线程返回唯一的ID。可以通过以下方式从Python访问 numba.np.ufunc.parallel._get_thread_id()(也可以在JIT编译函数中使用它)。线程ID函数对于测试线程屏蔽行为是否正确很有用,但不应在测试之外使用。例如,可以调用set_num_threads,收集_get_thread_id()并行区域中的所有唯一性,验证仅运行了4个线程。
注意事项
测试线程屏蔽时需要注意的一些注意事项:
• TBB后端可以选择调度少于给定掩码数的线程。因此,诸如上述测试,可能返回少于4个唯一线程。
• 工作队列后端不是线程安全的,因此尝试对其执行多线程嵌套并行处理,可能会导致死锁或其他未定义的行为。如果工作队列后端检测到嵌套的并行性,它将发出SIGABRT信号。
• 某些后端可能会重用主线程进行计算,但是不应依赖此行为(例如,如果传递异常)。
在代码生成中使用
get_num_threads在代码生成中使用的一般模式是
import llvmlite.llvmpy.core as lc

get_num_threads = builder.module.get_or_insert_function(
lc.Type.function(lc.Type.int(types.intp.bitwidth), []),
name=“get_num_threads”)

num_threads = builder.call(get_num_threads, [])

with cgutils.if_unlikely(builder, builder.icmp_signed(’<=’, num_threads,
num_threads.type(0))):
cgutils.printf(builder, “num_threads: %d\n”, num_threads)
context.call_conv.return_user_exc(builder, RuntimeError,
("Invalid number of threads. "
“This likely indicates a bug in Numba.”,))

# Pass num_threads through to the appropriate backend function here
请参阅中的代码numba/parfors/parfor_lowering.py。
num_threads严格禁止<= 0的防护措施是必要的,但是在线程屏蔽逻辑包含错误的情况下,它可以防止意外的错误行为。
该num_threads变量应传递给适当的后端函数,例如do_scheduling或parallel_for。如果以其它方式使用(而不是将其传递给后端函数),应考虑上述注意事项,确保num_threads安全使用变量。最好将这样的逻辑保留在线程后端中,而不是尝试在代码生成中进行。

关于Numba的线程实现的说明相关推荐

  1. 多线程编程指南 part 2

    多线程编程指南 Sun Microsystems, Inc. 4150 Network Circle Santa Clara, CA95054 U.S.A. 文件号码819–7051–10 2006 ...

  2. 适用于CUDA GPU的Numba例子

    • 适用于CUDA GPU的Numba例子 矩阵乘法 这是使用CUDA内核的矩阵乘法的简单实现: @cuda.jit def matmul(A, B, C): """Pe ...

  3. Python可以调用Gpu吗_加快Python算法的四个方法:Numba篇

    CDA数据分析师 出品 相信大家在做一些算法经常会被庞大的数据量所造成的超多计算量需要的时间而折磨的痛苦不已,接下来我们围绕四个方法来帮助大家加快一下Python的计算时间,减少大家在算法上的等待时间 ...

  4. Python Numba实现GPU加速

    Python与GPU Python作为解释型语言,.py文件一般是没法直接用GPU加速的,关于Python与GPU的结合点,以及GPU.CPU.CUDA.多核.并行.机器码-等底层实现,参考: < ...

  5. sqlserver循环like变量_numba从入门到精通(6)—numba与循环与并行

    多进程.多线程.并行的调用方式的不同以及python各种常用且优化较好的并行的处理方法,回头要总结一下,概念模糊很蒙蔽.我们这里介绍一下numba强大并且简单易用的并行功能. import numpy ...

  6. python gpu编程_Python笔记_第四篇_高阶编程_进程、线程、协程_5.GPU加速

    Numba:高性能计算的高生产率 在这篇文章中,笔者将向你介绍一个来自Anaconda的Python编译器Numba,它可以在CUDA-capable GPU或多核cpu上编译Python代码.Pyt ...

  7. Python数据预处理:使用Dask和Numba并行化加速

    摘要: 本文是针对Python设计一种并行处理数据的解决方案--使用Dask和Numba并行化加速运算速度.案例对比分析了几种不同方法的运算速度,非常直观,可供参考. 如果你善于使用Pandas变换数 ...

  8. Numba 0.44 中文文档校对活动 | ApacheCN

    整体进度:https://github.com/apachecn/numba-doc-zh/issues/1 贡献指南:https://github.com/apachecn/numba-doc-zh ...

  9. python numba 转灰度图_Python数据预处理:Dask和Numba并行化加速!

    如果你善于使用Pandas变换数据.创建特征以及清洗数据等,那么你就能够轻松地使用Dask和Numba并行加速你的工作.单纯从速度上比较,Dask完胜Python,而Numba打败Dask,那么Num ...

最新文章

  1. 汽车HUD(Head-up Display)的技术难点
  2. 基于SSM实现保健院管理系统
  3. MySQL查询指定字段
  4. 微信公众号支付开发全过程(java版)
  5. Netty实战 IM即时通讯系统(十一)pipeline与channelHandler
  6. DB2数据库性能调整和优化(第2版)
  7. 树莓派学习——文件传输
  8. Java LocalDate类| 带示例的format()方法
  9. 恢复初始快捷键_如何将Windows10系统还原初始状态
  10. c语言读取gps模块数据类型,GPS数据读取与处理(一)之GPS模块的数据格式
  11. 单场淘汰制场次计算方法_单循环淘汰赛什么意思?
  12. 丧钟为谁而鸣:AI步步逼近,华尔街23万人将失业
  13. 考研笔记——王道C语言
  14. 一、财务框架与基础知识
  15. 5G QoS控制原理专题详解-基础概念
  16. Node 学习六、核心模块 events之 01 events 和 EventEmitter 类、发布订阅、EventEmitter 类源码解析和模拟实现
  17. 7-4 到底是不是太胖了
  18. 团体程序设计天梯赛-练习集——7-10 彩虹瓶 (25分)
  19. Vue3+TypeScript从入门到精通系列之:Try changing the lib compiler option to es2015 or later
  20. 指定页面模式,避开IE兼容性问题

热门文章

  1. Strutsw2与Spring整合流程-简述
  2. 2022-2028年中国高阻隔片材基膜行业市场供需形势及前瞻分析报告
  3. Python 生成器总结
  4. 正视自己的所想所求,活出真实的自己
  5. 利用pandas读写HDF5文件
  6. 使用 Pytorch 实现 skip-gram 的 word2vec
  7. 自动调度GPU的卷积层
  8. Technology Document Guide of TensorRT
  9. 通往安全自动驾驶汽车的艰难道路
  10. 目标检测中特征融合技术(YOLO v4)(下)