• 用实力和真相精确测试python gil,证明只有多进程才能使用多核, 测试验证绝不含糊,不需要死记硬背意淫gil概念。杜绝空罐子不荡半罐子荡


    代码如下,先定义一个无限蒙蔽死循环消耗cpu的函数 f

    在一台4核cpu的linux上,分别直接 单进程单线程跑f函数,4进程跑f函数,4线程跑f函数,2进程程跑f函数,3进程跑f函数,50进程跑f函数

    from threading import Thread
    from multiprocessing import Process
    
    def f():  # 这是个无限蒙蔽死循环的函数,解释器一直高速在while 1和pass这两行代码之间快速运行,可以使单核cpu实用率达到100%
        while 1:
            # time.sleep(0.0001) # 哪怕是休眠0.1毫秒cpu也不至于占满,但没有休眠就会造成cpu超高速无限蒙蔽死循环
            pass
    
    if __name__ == '__main__':
       # f() # 直接单进程单线程跑函数
        for i in range(4):                # 改这个数字4可以测试几个进程和几核的关系,可以很精确测出来开多少进程最好
            Process(target=f , ).start()  # 多进程跑函数
            # Thread(target=f , ).start()  # 多线程跑函数

    linux cpu的总使用率是每个单核cpu加起来的总和,如果按照每个核cpu实用率相加的话,4核最多可以达到400%,如果总cpu采用100%来封顶计算那就总cpu是最高能100%

    4进程运行f函数的截图,

    可以看见系统多核总cpu使用率达到了100%,其中4个python3进程的cpu接近100%(因为系统中部署了其他的服务,也需要一些cpu消耗支撑)

    2进程运行f函数的截图,

    可以看见系统多核总cpu使用率达到了52%(几乎等于50%,多余的2%是其他软件消耗的),其中2个python3进程的cpu接近100%(因为系统中部署了其他的服务,也需要一些cpu消耗支

     

    3进程运行f函数的截图,

    可以看见系统多核总cpu使用率达到了77%(几乎等于75%,多余的2%是其他软件消耗的),其中3个python3进程的cpu接近100%(因为系统中部署了其他的服务,也需要一些cpu消耗支撑)

    单进程单线程(即使直接运行f函数)

    可以看见系统多核总cpu使用率达到了28%(几乎等于25%,多余的3%是其他软件消耗的),其中1个python3进程的cpu接近100%(因为系统中部署了其他的服务,也需要一些cpu消耗支撑)

    50进程运行f函数的截图,

    可以看见系统多核总cpu使用率达到了100%,其中有50个python3进程,但每个python3进程的cpu实用率无法达到100%,因为cpu的总使用率已近达到100%了无法更高了,因为你的电脑不是64核的,只是个4核而已

    这就是为什么要想电脑跑得快流畅,最好是花高价10万买5ghz主频 128核的电脑好,核心越多越好,主频越高越好,不然为什么流弊的电脑cpu卖那么贵,要是cpu核心数量没卵用,那为啥因特尔i9比i3贵十几倍?

    重头戏来了,4个线程(此处是线程Thread不是进程Process)运行f函数的截图,

    可以看见系统多核总cpu使用率达到了27%(几乎等于25%,多余的2%是其他软件消耗的),其中1个python3进程的cpu接近100%(因为系统中部署了其他的服务,也需要一些cpu消耗支撑)

    次函数无论是开1个线程 2个线程 4个线程 或者200线程,linux控制台只会显示单个python命令进程,cpu实用率是100%,总cpu实用率是25%。

    这就足以证明,如果想把这台linux系统发挥好,全部cpu打满,最好是开4进程,开1个线程和100个线程都一样无卵用,都是单核100%cpu,无法吧系统总cpu实用率达到100%

    总结就是,对于python gil说的是,只有多进程才能使用多核。

    对于Python gil 有三种人:

    第一种压根没听说gil ,自然也不知道gil概念,自然不知道为什么开多进程,这叫空罐子,这种码农占了30%

    空罐子有点坑,连这都不知道,自然在编程上不能发挥好电脑的全部性能,java的 多个Thread 可以把电脑的总cpu实用率占满到100%,但python无论开多少线程开一亿个线程都无法做到。非常简单的可以实测单个java.exe进程可以使8核cpu达到100%,单个python.exe进程最高只能让cpu达到12.5%,java从语言语法层级没有Process类,python有Thread和Proess类。

    第二种是听说过gil概念,但光是背诵一段别人博客上的概念(甚至别人博客上表达的压根是错误的),自己并没有真正搞懂,甚至对gil进行了意淫更是产生了错误的理解,这叫半罐子,这种码农占了60%

    半罐子更坑了,啥问题都扯在gil上,没真正明白为什么要开多进程。

    第三种就是既听说了gil,又真正理解gil,知道什么时候需要开多进程,知道为什么要开多进程,精通 "python的多线程是假的这句话" 这种模棱两可的表述是多么的操蛋,这叫满罐子,这种码农只有10%

    这种是最好的码农,无论是对任何场景io密集,cpu密集,还是io+cpu双密集,都能做到合理的多线程 多进程 协程 编程,最充分的发挥电脑性能。

    满罐子自然能通过这篇博客的实验代码和截图了解真正的gil是什么了。其实半罐子比空罐子还更坑爹,本来代码可以不那么慢,有的半罐子似是而非把原因怪罪在gil上,

    讲一下半罐子是咋样的,半罐子为什么那么荡:

    比如我见一个测试人员在公司的wiki文档上写了这么一句话,他使用python + slenium 做ui测试,它里面说的是开多个浏览器同时打开多个网页,一定要使用多进程不能使用多线程,因为python有gil,这句话就说的很操蛋了,python通过slenium操作浏览器,对于python来说是通过发送指令给driver,python本身的cpu消耗不大,cpu消耗大的是浏览器在渲染网页上,sleneium的谷歌浏览器渲染网页消耗的cpu又不是python进程本身,而是chrome.exe消耗cpu大。多线程操作多个浏览器绝对没毛病不会出错,所谓的python gil限制,必须使用多进程操作多个浏览器是瞎几把扯淡。这就是叫做空罐子不荡半罐子荡,没听说gil的人反而可能会使用多线程操作seleium浏览器。

    类似的 http 请求爬虫,半罐子荡的要命,半罐子说开多线程爬虫没卵用python多线程是假的,和单线程速度一模一样,说必须多进程爬虫才能快。说这话的傻了个瓜,你自己写个flask接口测试下很难吗,接口中sleep(20)秒,

    你单个线程请求接口1000次是不要2万秒,难道100线程请求接口1000次也要2万秒吗,应该是200秒就能请求完成1000次吧?

    对于爬虫多线程绝对是非常合适的甚至是最好的,如果没反扒那就 多线程+ 多进程同时搞起,因为requests包发送一次请求是很消耗cpu的,python requests单核请求任何http接口一秒钟都无法突破500次请求,python发送请求绝对是cpu密集型的,不要错以为如果服务端性能没瓶颈,requests单核一秒钟就可以发送1万次请求,更何况解析网页超长的字符串内容也是需要时间的,爬虫发送请求绝对是cpu密集型 + io密集型,如果网站没反扒,接口响应时间大,你想实现万次爬虫每秒(假设网速无限很快),就必须多进程+ 多线程同时搞起,这样成分绕过io充分并使用多核cpu。

    如果你网站有反扒,接口响应时间大,那就多线程开50个就行了,绝对比开50进程好,多进程消耗cpu和内存过大。

    通过以上2个例子说明一下对于gil,半罐子比空罐子问题其实更严重,半罐子不要把python啥东西都怪在gil头上。

    说道这里,因为上面举了个爬虫多进程和多线程例子,有些人故意扯到协程了,骂我说只有协程爬虫才是最快的,你居然扯到gevent asyncio了,上面讲的多进程和gil和这协程没有办毛钱关系吗?

    协程是不错,但是你想吊打多线程没那么容易,别光意淫多线程频繁切换上下文要消耗时间,这个时间具体时间多大,对于爬虫网站接口的io响应时间是多大要弄清楚,如果python多线程切换速度比网站io响应小太多了,几乎忽略不计了,你还计较啥上下文切换,多线程就对了,不要搞虚头巴脑的协程增加编程复杂度。

    这篇文章主要是讲什么是gil,和为什么要开多进程,开多少个进程最好,既然你还是死不瞑目非要和这篇文章扯啥协程的,那就看看本人发明的史上最牛的 python http 请求客户端,这里面有测试现成的例子,这个包封装的简单,发送单个请求由于消耗的代码少,所以单次请求cpu实用率比别的包低很多,无论你采用gevnt + urllib 还是 asyncio+aiohttp,每秒请求次数的上限,你会发现都被nb_http_client + 多线程 轻松吊打,不服的可以试试来任何协程代码挑战我这个线程池+nb_http_client请求,如果你能比我快我陪你一个mac笔记本,如果不能,你陪我一个红米笔记本就行。  

    吊打任何协程的   多线程 + nb_hhtp_client 请求  ,地址   https://github.com/ydf0509/nb_http_client,不信的可以自己亲自测试。

    希望通过这篇文章,有代码有图有真相,讲明白 什么是gil,和为什么要开多进程,开多少个进程最好!彻底解决空罐子和半罐子问题。

    反对极端面向过程编程思维方式,喜欢面向对象和设计模式的解读,喜欢对比极端面向过程编程和oop编程消耗代码代码行数的区别和原因。致力于使用oop和36种设计模式写出最高可复用的框架级代码和使用最少的代码行数完成任务,致力于使用oop和设计模式来使部分代码减少90%行,使绝大部分py文件最低减少50%-80%行的写法。
  • 相关阅读:
    【马克-to-win】学习笔记—— 第五章 异常Exception
    【马克-to-win】—— 学习笔记
    Eclipse 日文乱码怎么解决Shift_JIS
    DB2设置code page(日文943)
    如何得到一个接口所有的实现类(及子接口)?例如:Eclipse IDE
    【VBA】随机数
    【VBA】利用Range声明Array(一维/二维)
    【VBA】Do While……Loop循环,遍历某列
    【58沈剑架构系列】DB主从一致性架构优化4种方法
    【58沈剑架构系列】主从DB与cache一致性
  • 原文地址:https://www.cnblogs.com/ydf0509/p/15558229.html
Copyright © 2020-2023  润新知