如何让python 提高cpu使用率使用全部cpu

匿名用户不能发表回复!|
每天回帖即可获得10分可用分!小技巧:
你还可以输入10000个字符
(Ctrl+Enter)
请遵守CSDN,不得违反国家法律法规。
转载文章请注明出自“CSDN(www.csdn.net)”。如是商业用途请联系原作者。lu4nx@wiki
Python获得CPU核数的方法
准确来说,获得的不是核心(Core)数,而是并发的线程数。在multiprocessing模块中的cpu_count()函数已经实现了该功能,函数的源码如下:
def cpu_count():
Returns the number of CPUs in the system
if sys.platform == 'win32':
#我很好奇64bit的windows是不是也是win32
num = int(os.environ['NUMBER_OF_PROCESSORS'])
except (ValueError, KeyError):
elif 'bsd' in sys.platform or sys.platform == 'darwin':
comm = '/sbin/sysctl -n hw.ncpu'
if sys.platform == 'darwin':
comm = '/usr' + comm
with os.popen(comm) as p:
num = int(p.read())
except ValueError:
num = os.sysconf('SC_NPROCESSORS_ONLN')
except (ValueError, OSError, AttributeError):
if num &= 1:
return num
raise NotImplementedError('cannot determine number of cpus')
如果是Windows环境,则从环境变量NUMBER_OF_PROCESSORS中得到CPU线程数量;如果是BSD或者Mac OS,则是执行sysctl -n hw.ncpu(注意Mac OS的是在/usr/sbin/sysctl -n hw.ncpu中);如果是其他系统(一般就剩下Linux了),则执行os.sysconf('SC_NPROCESSORS_ONLN')得到。
本站文章如未特殊声明,默认采用进行许可。2010年6月 其他开发语言大版内专家分月排行榜第三2009年9月 C/C++大版内专家分月排行榜第三
2010年6月 其他开发语言大版内专家分月排行榜第三2009年9月 C/C++大版内专家分月排行榜第三
本帖子已过去太久远了,不再提供回复功能。原文链接/stubborn412/p/4033651.html
GIL 与 Python 线程的纠葛
GIL 是什么东西?它对我们的 python 程序会产生什么样的影响?我们先来看一个问题。运行下面这段 python 程序,CPU 占用率是多少?
# 请勿在工作中模仿,危险:)
def dead_loop():
while True:
dead_loop()
答案是什么呢,占用 100% CPU?那是单核!还得是没有超线程的古董 CPU。在我的双核 CPU 上,这个死循环只会吃掉我一个核的工作负荷,也就是只占用 50% CPU。那如何能让它在双核机器上占用 100% 的 CPU 呢?答案很容易想到,用两个线程就行了,线程不正是并发分享 CPU 运算资源的吗。可惜答案虽然对了,但做起来可没那么简单。下面的程序在主线程之外又起了一个死循环的线程
import threading
def dead_loop():
while True:
# 新起一个死循环线程
t = threading.Thread(target=dead_loop)
# 主线程也进入死循环
dead_loop()
按道理它应该能做到占用两个核的 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 写一个死循环函数
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)
lib.DeadLoop()
这回再看看 system monitor,Python 解释器进程有两个线程在跑,而且双核 CPU 全被占满了,ctypes 确实很给力!需要提醒的是,GIL 是被 ctypes 在调用 C 函数前释放的。但是 Python 解释器还是会在执行任意一段 Python 代码时锁 GIL 的。如果你使用 Python 的代码做为 C 函数的 callback,那么只要 Python 的 callback 方法被执行时,GIL 还是会跳出来的。比如下面的例子:
typedef void Callback();
void Call(Callback* callback)
callback();
from ctypes import *
from threading import Thread
def dead_loop():
while True:
lib = cdll.LoadLibrary(&libcall.so&)
Callback = CFUNCTYPE(None)
callback = Callback(dead_loop)
t = Thread(target=lib.Call, args=(callback,))
lib.Call(callback)
注意这里与上个例子的不同之处,这次的死循环是发生在 Python 代码里 (DeadLoop&函数) 而 C 代码只是负责去调用这个 callback 而已。运行这个例子,你会发现 CPU 占用率还是只有 50% 不到。GIL 又起作用了。
其实,从上面的例子,我们还能看出 ctypes 的一个应用,那就是用 Python 写自动化测试用例,通过 ctypes 直接调用 C 模块的接口来对这个模块进行黑盒测试,哪怕是有关该模块 C 接口的多线程安全方面的测试,ctypes 也一样能做到。
虽然 CPython 的线程库封装了操作系统的原生线程,但却因为 GIL 的存在导致多线程不能利用多个 CPU 内核的计算能力。好在现在 Python 有了易经筋(multiprocessing), 吸星大法(C 语言扩展机制)和独孤九剑(ctypes),足以应付多核时代的挑战,GIL 切还是不切已经不重要了,不是吗。
本文已收录于以下专栏:
相关文章推荐
总结一下之前的项目,主要用到了python多进程的知识,其他的一些零碎的辅助知识也会用到,这里主要对整体框架进行总结,至于性能,因为经验问题,不能优化的很好,加上本项目有很多文件的读写,只能算稳定而已...
为啥要这个模块:
Python是解释型的语言,而Python解释器使用GIL(全局解 释器锁)来在内部禁止并行执行,正是这个GIL限制你在多核处理器上同一时间也只能执行一条字节码指令. 听朋友说...
1. 最近公司用有个比较奇怪的需求,需要在流水中查找某一条符合条件的流水记录,记录是在hdfs上的,按天存在文件中,但是文件都比较大,每天大概是25G的流水数据,现在提供刷卡回执单去查找该消费记录在我...
多核CPU上python多线程并行的一个假象
python-cn(华蟒用户组,CPyUG 邮件列表)上: 关于
python 多线程是否能用到多核的问题 相关讨论
本机环境: 2核CPU,...
原文:/python/377686.html
; addons模块的查找路径
addons_path = E:\GreenOdoo8.0\source\openerp\addons
; 管理员主控密码(用于创建、还原和备份数据...
原文地址:http://my.oschina.net/u/240562/blog/136651
GIL 与 Python 线程的纠葛
GIL 是什么东西?它对我们的 pyt...
一直以为java线程开得越多效率越高,后来知道了执行的效率和cpu核心数有关,今天试了下多核cpu下多线程的计算:
本机i5四核,分别开启1、4、10、20、40、100、400个线程做100W次,m...
他的最新文章
讲师:汪剑
讲师:刘道宽
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)使用Python获取CPU、内存和硬盘等windowns系统信息的2个例子
字体:[ ] 类型:转载 时间:
这篇文章主要介绍了使用Python获取CPU、内存和硬盘等windowns系统信息的2个例子,使用的python wmi模块,需要的朋友可以参考下
Python用WMI模块获取windowns系统的硬件信息:硬盘分区、使用情况,内存大小,CPU型号,当前运行的进程,自启动程序及位置,系统的版本等信息。
代码如下:#!/usr/bin/env python # -*- coding: utf-8 -*- import wmi import os import sys import platform import time def sys_version():& &&& c = wmi.WMI () &&& #获取操作系统版本 &&& for sys in c.Win32_OperatingSystem(): &&&&&&& print "Version:%s" % sys.Caption.encode("UTF8"),"Vernum:%s" % sys.BuildNumber &&&&&&& print& sys.OSArchitecture.encode("UTF8")#系统是32位还是64位的 &&&&&&& print sys.NumberOfProcesses #当前系统运行的进程总数def cpu_mem(): &&& c = wmi.WMI ()&&&&&&& &&& #CPU类型和内存 &&& for processor in c.Win32_Processor(): &&&&&&& #print "Processor ID: %s" % processor.DeviceID &&&&&&& print "Process Name: %s" % processor.Name.strip() &&& for Memory in c.Win32_PhysicalMemory(): &&&&&&& print "Memory Capacity: %.fMB" %(int(Memory.Capacity)/1048576) def cpu_use(): &&& #5s取一次CPU的使用率 &&& c = wmi.WMI() &&& while True: &&&&&&& for cpu in c.Win32_Processor(): &&&&&&&&&&&& timestamp = time.strftime('%a, %d %b %Y %H:%M:%S', time.localtime()) &&&&&&&&&&&& print '%s | Utilization: %s: %d %%' % (timestamp, cpu.DeviceID, cpu.LoadPercentage) &&&&&&&&&&&& time.sleep(5)&&&& def disk(): &&& c = wmi.WMI ()&&& &&& #获取硬盘分区 &&& for physical_disk in c.Win32_DiskDrive (): &&&&&&& for partition in physical_disk.associators ("Win32_DiskDriveToDiskPartition"): &&&&&&&&&&& for logical_disk in partition.associators ("Win32_LogicalDiskToPartition"): &&&&&&&&&&&&&&& print physical_disk.Caption.encode("UTF8"), partition.Caption.encode("UTF8"), logical_disk.Caption &&& #获取硬盘使用百分情况 &&& for disk in c.Win32_LogicalDisk (DriveType=3): &&&&&&& print disk.Caption, "%0.2f%% free" % (100.0 * long (disk.FreeSpace) / long (disk.Size)) def network(): &&& c = wmi.WMI ()&&&& &&& #获取MAC和IP地址 &&& for interface in c.Win32_NetworkAdapterConfiguration (IPEnabled=1): &&&&&&& print "MAC: %s" % interface.MACAddress &&& for ip_address in interface.IPAddress: &&&&&&& print "ip_add: %s" % ip_address &&& print &&& #获取自启动程序的位置 &&& for s in c.Win32_StartupCommand (): &&&&&&& print "[%s] %s &%s&" % (s.Location.encode("UTF8"), s.Caption.encode("UTF8"), s.Command.encode("UTF8"))& &&&& &&& #获取当前运行的进程 &&& for process in c.Win32_Process (): &&&&&&& print process.ProcessId, process.Name def main(): &&& sys_version() &&& #cpu_mem() &&& #disk() &&& #network() &&& #cpu_use() if __name__ == '__main__': &&& main() &&& print platform.system() &&& print platform.release() &&& print platform.version() &&& print platform.platform() &&& print platform.machine()
由于我用到的不多,所以只获取的CPU、内存和硬盘,如果需要其它资源,请参照msdn。
代码如下:import osimport win32apiimport win32conimport wmiimport time
def getSysInfo(wmiService = None):&&& result = {}&&& if wmiService == None:&&&&&&& wmiService = wmi.WMI()&&& # cpu&&& for cpu in wmiService.Win32_Processor():&&&&&&& timestamp = time.strftime('%a, %d %b %Y %H:%M:%S', time.localtime())&&&&&&& result['cpuPercent'] = cpu.loadPercentage&&& # memory&&& cs = wmiService.Win32_ComputerSystem()&&& os = wmiService.Win32_OperatingSystem()&&& result['memTotal'] = int(int(cs[0].TotalPhysicalMemory)/)&&& result['memFree'] = int(int(os[0].FreePhysicalMemory)/1024)&&& #disk&&& result['diskTotal'] = 0&&& result['diskFree'] = 0&&& for disk in wmiService.Win32_LogicalDisk(DriveType=3):&&&&&&& result['diskTotal'] += int(disk.Size)&&&&&&& result['diskFree'] += int(disk.FreeSpace)&&& result['diskTotal'] = int(result['diskTotal']/)&&& result['diskFree'] = int(result['diskFree']/)&&& return result
if __name__ == '__main__':&&& wmiService = wmi.WMI()&&& while True:&&&&&&& print getSysInfo(wmiService)&&&&&&& time.sleep(3)
采用的wmi模块获取的,由于wmi初始化时占用系统资源太高,所以如果需要循环获取,请在循环体外面把wmi对象初始化好,然后传入函数里面,这样就不会产生CPU资源过高的情况。
您可能感兴趣的文章:
大家感兴趣的内容
12345678910
最近更新的内容
常用在线小工具

我要回帖

更多关于 python监控cpu使用率 的文章

 

随机推荐