返回顶部
首页 > 资讯 > 后端开发 > Python >Python怎么利用多核cpu
  • 453
分享到

Python怎么利用多核cpu

多核Pythoncpu 2023-01-31 03:01:28 453人浏览 独家记忆

Python 官方文档:入门教程 => 点击学习

摘要

原文链接Http://www.cnblogs.com/stubborn412/p/4033651.html GIL 与 python 线程的纠葛 GIL 是什么东西?它对我们的 Python 程序会产生什么样的影响?我们先来看一个问

原文链接Http://www.cnblogs.com/stubborn412/p/4033651.html

GIL 与 python 线程的纠葛

GIL 是什么东西?它对我们的 Python 程序会产生什么样的影响?我们先来看一个问题。运行下面这段 python 程序,CPU 占用率是多少?

# 请勿在工作中模仿,危险:)
def dead_loop():
    while True:
        pass

dead_loop()

答案是什么呢,占用 100% CPU?那是单核!还得是没有超线程的古董 CPU。在我的双核 CPU 上,这个死循环只会吃掉我一个核的工作负荷,也就是只占用 50% CPU。那如何能让它在双核机器上占用 100% 的 CPU 呢?答案很容易想到,用两个线程就行了,线程不正是并发分享 CPU 运算资源的吗。可惜答案虽然对了,但做起来可没那么简单。下面的程序在主线程之外又起了一个死循环的线程

import threading

def dead_loop():
    while True:
        pass

# 新起一个死循环线程
t = threading.Thread(target=dead_loop)
t.start()

# 主线程也进入死循环
dead_loop()

t.join()

按道理它应该能做到占用两个核的 CPU 资源,可是实际运行情况却是没有什么改变,还是只占了 50% CPU 不到。这又是为什么呢?难道 python 线程不是操作系统的原生线程?打开 system monitor 一探究竟,这个占了 50% 的 python 进程确实是有两个线程在跑。那这两个死循环的线程为何不能占满双核 CPU 资源呢?其实幕后的黑手就是 GIL。

GIL 的迷思:痛并快乐着

GIL 的全称为 Global Interpreter Lock ,意即全局解释器。在 Python 语言的主流实现 CPython 中,GIL 是一个货真价实的全局线程锁,在解释器解释执行任何 Python 代码时,都需要先获得这把锁才行,在遇到 I/O 操作时会释放这把锁。如果是纯计算的程序,没有 I/O 操作,解释器会每隔 100 次操作就释放这把锁,让别的线程有机会执行(这个次数可以通过sys.setcheckinterval 来调整)。所以虽然 CPython 的线程库直接封装操作系统的原生线程,但 CPython 进程做为一个整体,同一时间只会有一个获得了 GIL 的线程在跑,其它的线程都处于等待状态等着 GIL 的释放。这也就解释了我们上面的实验结果:虽然有两个死循环的线程,而且有两个物理 CPU 内核,但因为 GIL 的限制,两个线程只是做着分时切换,总的 CPU 占用率还略低于 50%。

看起来 python 很不给力啊。GIL 直接导致 CPython 不能利用物理多核的性能加速运算。那为什么会有这样的设计呢?我猜想应该还是历史遗留问题。多核 CPU 在 1990 年代还属于类科幻,Guido van Rossum 在创造 python 的时候,也想不到他的语言有一天会被用到很可能 1000+ 个核的 CPU 上面,一个全局锁搞定多线程安全在那个时代应该是最简单经济的设计了。简单而又能满足需求,那就是合适的设计(对设计来说,应该只有合适与否,而没有好与不好)。怪只怪硬件的发展实在太快了,摩尔定律给软件业的红利这么快就要到头了。短短 20 年不到,代码工人就不能指望仅仅靠升级 CPU 就能让老软件跑的更快了。在多核时代,编程的免费午餐没有了。如果程序不能用并发挤干每个核的运算性能,那就意谓着会被淘汰。对软件如此,对语言也是一样。那 Python 的对策呢?

Python 的应对很简单,以不变应万变。在最新的 python 3 中依然有 GIL。之所以不去掉,原因嘛,不外以下几点:

  • 欲练神功,挥刀自宫:

    CPython 的 GIL 本意是用来保护所有全局的解释器和环境状态变量的。如果去掉 GIL,就需要多个更细粒度的锁对解释器的众多全局状态进行保护。或者采用 Lock-Free 算法。无论哪一种,要做到多线程安全都会比单使用 GIL 一个锁要难的多。而且改动的对象还是有 20 年历史的 CPython 代码树,更不论有这么多第三方的扩展也在依赖 GIL。对 Python 社区来说,这不异于挥刀自宫,重新来过。

  • 就算自宫,也未必成功:

    有位牛人曾经做了一个验证用的 CPython,将 GIL 去掉,加入了更多的细粒度锁。但是经过实际的测试,对单线程程序来说,这个版本有很大的性能下降,只有在利用的物理 CPU 超过一定数目后,才会比 GIL 版本的性能好。这也难怪。单线程本来就不需要什么锁。单就锁管理本身来说,锁 GIL 这个粗粒度的锁肯定比管理众多细粒度的锁要快的多。而现在绝大部分的 python 程序都是单线程的。再者,从需求来说,使用 python 绝不是因为看中它的运算性能。就算能利用多核,它的性能也不可能和 C/C++ 比肩。费了大力气把 GIL 拿掉,反而让大部分的程序都变慢了,这不是南辕北辙吗。

  • 难道 Python 这么优秀的语言真的仅仅因为改动困难和意义不大就放弃多核时代了吗?其实,不做改动最最重要的原因还在于:不用自宫,也一样能成功!

其它神功

那除了切掉 GIL 外,果然还有方法让 Python 在多核时代活的滋润?让我们回到本文最初的那个问题:如何能让这个死循环的 Python 脚本在双核机器上占用 100% 的 CPU?其实最简单的答案应该是:运行两个 python 死循环的程序!也就是说,用两个分别占满一个 CPU 内核的 python 进程来做到。确实,多进程也是利用多个 CPU 的好方法。只是进程间内存地址空间独立,互相协同通信要比多线程麻烦很多。有感于此,Python 在 2.6 里新引入了 multiprocessing这个多进程标准库,让多进程的 python 程序编写简化到类似多线程的程度,大大减轻了 GIL 带来的不能利用多核的尴尬。

这还只是一个方法,如果不想用多进程这样重量级的解决方案,还有个更彻底的方案,放弃 Python,改用 C/c++。当然,你也不用做的这么绝,只需要把关键部分用 C/C++ 写成 Python 扩展,其它部分还是用 Python 来写,让 Python 的归 Python,C 的归 C。一般计算密集性的程序都会用 C 代码编写并通过扩展的方式集成到 Python 脚本里(如 NumPy 模块)。在扩展里就完全可以用 C 创建原生线程,而且不用锁 GIL,充分利用 CPU 的计算资源了。不过,写 Python 扩展总是让人觉得很复杂。好在 Python 还有另一种与 C 模块进行互通的机制 : ctypes

利用 ctypes 绕过 GIL

ctypes 与 Python 扩展不同,它可以让 Python 直接调用任意的 C 动态库的导出函数。你所要做的只是用 ctypes 写些 python 代码即可。最酷的是,ctypes 会在调用 C 函数前释放 GIL。所以,我们可以通过 ctypes 和 C 动态库来让 python 充分利用物理内核的计算能力。让我们来实际验证一下,这次我们用 C 写一个死循环函数

extern"C"
{
  void DeadLoop()
  {
    while (true);
  }
}

用上面的 C 代码编译生成动态库 libdead_loop.so (windows 上是 dead_loop.dll

,接着就要利用 ctypes 来在 python 里 load 这个动态库,分别在主线程和新建线程里调用其中的 DeadLoop

from ctypes import *
from threading import Thread

lib = cdll.LoadLibrary("libdead_loop.so")
t = Thread(target=lib.DeadLoop)
t.start()

lib.DeadLoop()

这回再看看 system monitor,Python 解释器进程有两个线程在跑,而且双核 CPU 全被占满了,ctypes 确实很给力!需要提醒的是,GIL 是被 ctypes 在调用 C 函数前释放的。但是 Python 解释器还是会在执行任意一段 Python 代码时锁 GIL 的。如果你使用 Python 的代码做为 C 函数的 callback,那么只要 Python 的 callback 方法被执行时,GIL 还是会跳出来的。比如下面的例子:

extern"C"
{
  typedef void Callback();
  void Call(Callback* callback)
  {
    callback();
  }
}
from ctypes import *
from threading import Thread

def dead_loop():
    while True:
        pass

lib = cdll.LoadLibrary("libcall.so")
Callback = CFUNCTYPE(None)
callback = Callback(dead_loop)

t = Thread(target=lib.Call, args=(callback,))
t.start()

lib.Call(callback)

注意这里与上个例子的不同之处,这次的死循环是发生在 Python 代码里 (DeadLoop 函数) 而 C 代码只是负责去调用这个 callback 而已。运行这个例子,你会发现 CPU 占用率还是只有 50% 不到。GIL 又起作用了。

其实,从上面的例子,我们还能看出 ctypes 的一个应用,那就是用 Python 写自动化测试用例,通过 ctypes 直接调用 C 模块的接口来对这个模块进行黑盒测试,哪怕是有关该模块 C 接口的多线程安全方面的测试,ctypes 也一样能做到。

结语

虽然 CPython 的线程库封装了操作系统的原生线程,但却因为 GIL 的存在导致多线程不能利用多个 CPU 内核的计算能力。好在现在 Python 有了易经筋(multiprocessing), 吸星大法(C 语言扩展机制)和独孤九剑(ctypes),足以应付多核时代的挑战,GIL 切还是不切已经不重要了,不是吗。


--结束END--

本文标题: Python怎么利用多核cpu

本文链接: https://lsjlt.com/news/187222.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • Python怎么利用多核cpu
    原文链接http://www.cnblogs.com/stubborn412/p/4033651.html GIL 与 Python 线程的纠葛 GIL 是什么东西?它对我们的 python 程序会产生什么样的影响?我们先来看一个问...
    99+
    2023-01-31
    多核 Python cpu
  • python多线程对多核cpu的利用解析
    目录引言没有运行这段代码前cpu状态运行之后的状态运行代码结果python线程的执行流程理解遇到IO也会释放GIL引言 我们经常听到"因为GIL的存在,python的多线程...
    99+
    2024-04-02
  • 想要利用CPU多核资源
    本篇内容介绍了“想要利用CPU多核资源”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成! 大纲使用多进程的原因创建多进程的两种方式守护...
    99+
    2023-06-15
  • node.js如何充分利用多核cpu
    目录概述node.js充分利用多核cpu的方法Node创建子进程的4种方式概述 Nodejs是基于chrome浏览器的V8引擎构建的,也就说明它的模型与浏览器是类似的。我们的Java...
    99+
    2024-04-02
  • python怎么查看cpu的核数
    本文小编为大家详细介绍“python怎么查看cpu的核数”,内容详细,步骤清晰,细节处理妥当,希望这篇“python怎么查看cpu的核数”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。如何查看cpu的核数代码:&n...
    99+
    2023-06-30
  • PHP 数组并行排序:利用多核 CPU 提升性能
    对于大型数组,php 并行排序通过利用多核 cpu,比串行排序显著更快。该算法将数组拆分为多个段,同时在多个核心上排序,再合并成有序数组。利用 parallel\runtime 库中的 ...
    99+
    2024-04-27
    php 并行排序 composer
  • C++并发编程:如何利用多核CPU实现并发?
    c++++ 并发编程通过创建线程、互斥锁和条件变量来充分利用多核 cpu 的优势。创建线程允许任务并行执行。互斥锁充当锁,确保共享数据不会被多个线程同时访问,从而避免数据损坏。条件变量用...
    99+
    2024-05-01
    c++ 并发编程 并发访问
  • 如何利用多核CPU来加速你的Linux命令(GNU Parallel)
    你是否曾经有过要计算一个非常大的数据(几百GB)的需求ZEchYswiJ?或在里面搜索,或其它操作——一些无法并行的操作。数据专家们,我是在对你们说。你可能有一个4核或更多核的CPU,但我们合适的工具,例如 grep, ...
    99+
    2022-06-04
    GNU Parallel 多核CPU加速Linux命令
  • Go 语言中如何利用多核 CPU 实现并行计算
    本篇文章给大家分享的是有关Go 语言中如何利用多核 CPU 实现并行计算,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。开始之前,我们先澄清两个概念,「多核」指的是有效利用 CP...
    99+
    2023-06-20
  • nodejs线上如何使用多核cpu
    随着计算机硬件技术的不断更新,处理器的核心数也在逐步增多。现在,许多计算机都配备了多核CPU,这使得我们能够更有效地利用计算机资源来加快应用程序的处理速度。但是,要想充分利用多核CPU,需要对应用程序进行优化。本文将介绍如何在Node.js...
    99+
    2023-05-18
  • cpu利用率多少正常
    正常情况下,CPU利用率应该保持在较低的水平,通常在10%至30%之间。然而,具体的正常范围取决于计算机的配置和当前运行的应用程序。...
    99+
    2023-09-05
    cpu
  • Python多线程无法利用多核的原因是什么
    这篇文章主要讲解了“Python多线程无法利用多核的原因是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Python多线程无法利用多核的原因是什么”吧!1.全局解释锁如题: Python...
    99+
    2023-06-16
  • 云服务器cpu核数多少够用
    云服务器的CPU核数是由其提供的云服务器功能数量和计算资源来决定的,因此不同的云服务器提供商所提供的云服务器CPU核数有所不同。 但是,对于一些大型的云服务器提供商,其会根据自己的需要和使用经验来确定所需要的CPU核数,例如: 使用多核...
    99+
    2023-10-27
    服务器 cpu
  • Linux怎么查看CPU核数
    Linux下可以通过以下命令来查看CPU核数:1. 使用lscpu命令来查看CPU信息,包括核数:```lscpu```2. 使用n...
    99+
    2023-08-23
    Linux
  • Linux中怎么获取cpu利用率
    今天就跟大家聊聊有关Linux中怎么获取cpu利用率,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。1、从/proc文件系统获取相关的性能参数cpu使用率: /proc/stat内存使...
    99+
    2023-06-16
  • cpu利用率是什么
    cpu利用率是计算机中央处理单元的工作负载与其可用处理能力之间的比例,CPU利用率在10%-30%之间是比较正常的,优化CPU利用率的方法:1、升级计算机的硬件配置,如增加CPU核心数、提升CPU频率等;2、关闭那些不需要的进程和应用程序可...
    99+
    2023-07-10
  • 怎么在windows10中查看cpu有几核
    在windows10中查看cpu核数的方法:1.打开设备管理器;2.点击“处理器”选项;3.查看cpu核数;具体步骤如下:首先,在windows10系统中使用组合键“win+R”运行“devmgmt.msc”,打开设备管理器;进入到设备管理...
    99+
    2024-04-02
  • win7怎么设置CPU处理器核数?
    怎么设置cpu处理器核数呢?一般的电脑都是2核及以上,最大核心数8核,我们可以自由设置CPU处 1、在开始菜单中,打开运行,如图 2、输入msconfig,点击确定, 3、选择引导, 4、点击高级选项,如图 5、...
    99+
    2023-05-22
    win7 CPU 处理器
  • VBS中怎么利用WMI获取CPU使用率
    本篇文章为大家展示了VBS中怎么利用WMI获取CPU使用率,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。代码如下:On Error Resume Next strComputer = "....
    99+
    2023-06-08
  • linux怎么查看cpu个数和核心数
    在Linux系统中,可以使用以下命令来查看CPU个数和核心数:1. 使用lscpu命令:```lscpu```该命令会显示详细的CP...
    99+
    2023-09-16
    linux
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作