热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

python学习笔记day104【问题:为什么python的多线程不能利用多核CPU?】

为什么python的多线程不能利用多核CPU,但是咱们在写代码的时候,多线程的确是在并发,而且还比单线程快。一、python的多线程不能利

 为什么python的多线程不能利用多核CPU,但是咱们在写代码的时候,多线程的确是在并发,而且还比单线程快。

 

一、python的多线程不能利用多核CPU?

原因:因为GIL,python只有一个GIL,运行python时,就要拿到这个锁才能执行,在遇到I/O 操作时会释放这把锁。
如果是纯计算的程序,没有 I/O 操作,解释器会每隔100次操作就释放这把锁,让别的线程有机会 执行(这个次数可以通sys.setcheckinterval
来调整)同一时间只会有一个获得GIL线程在跑,其他线程都处于等待状态
1、如果是CPU密集型代码(循环、计算等),由于计算工作量多和大,计算很快就会达到100,然后触发GIL的释放与在竞争,多个线程来回切换损耗资源,
所以在多线程遇到CPU密集型代码时,单线程会比较快
2、如果是I\O密集型代码(文件处理、网络爬虫),开启多线程实际上是并发(不是并行),IO操作会进行IO等待,线程A等待时,自动切换到线程B,
这样就提升了效率

 

二、其他原理解释

转:链接:https://www.zhihu.com/question/23474039/answer/24695447

地说就是作为可能是仅有的支持多线程的解释型语言(perl的多线程是残疾,PHP没有多线程),Python的多线程是有compromise的,在任意时间只有一个Python解释器在解释Python bytecode。

如评论指出,Ruby也是有thread支持的,而且至少Ruby MRI是有GIL的。如果你的代码是CPU密集型,多个线程的代码很有可能是线性执行的。所以这种情况下多线程是鸡肋,效率可能还不如单线程因为有context switch但是:
如果你的代码是IO密集型,多线程可以明显提高效率。例如制作爬虫,绝大多数时间爬虫是在等待socket返回数据。这个时候C代码里是有release GIL的,最终结果是某个线程等待IO的时候其他线程可以继续执行。
反过来讲:你就不应该用Python写CPU密集型的代码…效率摆在那里…如果确实需要在CPU密集型的代码里用concurrent,就去用multiprocessing库。这个库是基于multi process实现了类multi thread的API接口,
并且用pickle部分地实现了变量共享。再加一条,如果你不知道你的代码到底算CPU密集型还是IO密集型,

教你个方法:multiprocessing这个module有一个dummy的sub module,它是基于multithread实现了multiprocessing的API。

假设你使用的是multiprocessing的Pool,是使用多进程实现了concurrency
from multiprocessing
import Pool
如果把这个代码改成下面这样,就变成多线程实现concurrency

from multiprocessing.dummy
import Pool
两种方式都跑一下,哪个速度快用哪个就行了。


转: 链接:https:
//www.zhihu.com/question/23474039/answer/269526476在介绍Python中的线程之前,先明确一个问题,Python中的多线程是假的多线程! 为什么这么说,我们先明确一个概念,全局解释器锁(GIL)。

Python代码的执行由Python虚拟机(解释器)来控制。Python在设计之初就考虑要在主循环中,同时只有一个线程在执行,就像单CPU的系统中运行多个进程那样,内存中可以存放多个程序,但任意时刻,只有一个程序在CPU中运行。
同样地,虽然Python解释器可以运行多个线程,只有一个线程在解释器中运行。对Python虚拟机的访问由全局解释器锁(GIL)来控制,正是这个锁能保证同时只有一个线程在运行。

在多线程环境中,Python虚拟机按照以下方式执行。

1.设置GIL。
2.切换到一个线程去执行。
3.运行。
4.把线程设置为睡眠状态。
5.解锁GIL。
6.再次重复以上步骤。

对所有面向I/O的(会调用内建的操作系统C代码的)程序来说,GIL会在这个I/O调用之前被释放,以允许其他线程在这个线程等待I/O的时候运行。如果某线程并未使用很多I/O操作,它会在自己的时间片内一直占用处理器和GIL。
也就是说,I/O密集型的Python程序比计算密集型的Python程序更能充分利用多线程的好处。我们都知道,比方我有一个4核的CPU,那么这样一来,在单位时间内每个核只能跑一个线程,然后时间片轮转切换。
但是Python不一样,它不管你有几个核,单位时间多个核只能跑一个线程,然后时间片轮转。看起来很不可思议?但是这就是GIL搞的鬼。任何Python线程执行前,必须先获得GIL锁,然后,每执行100条字节码,解释器就自动释放GIL锁,
让别的线程有机会执行。这个GIL全局锁实际上把所有线程的执行代码都给上了锁,所以,多线程在Python中只能交替执行,即使100个线程跑在100核CPU上,也只能用到1个核。通常我们用的解释器是官方实现的CPython,要真正利用多核,除非重写一个不带GIL的解释器。

我们不妨做个试验:

#coding=utf-8 from multiprocessing
import Pool from threading
import Thread from multiprocessing
import Process
def loop():
while True:
pass
if __name__ == '__main__':
for i in range(3):
t = Thread(target=loop)
t.start()
while True:
pass


我们发现CPU利用率并没有占满,大致相当于单核水平。

而如果我们变成进程呢?

我们改一下代码:

#coding=utf-8 from multiprocessing
import Pool from threading
import Thread from multiprocessing
import Process
def loop():
while True:
pass
if __name__ == '__main__':
for i in range(3):
t = Process(target=loop)
t.start()
while True:
pass


结果直接飙到了100%,说明进程是可以利用多核的!

为了验证这是Python中的GIL搞得鬼,我试着用Java写相同的代码,开启线程,我们观察一下

 

package com.darrenchan.thread;public class TestThread {public static void main(String[] args) {for (int i &#61; 0; i <3; i&#43;&#43;) {new Thread(new Runnable() {&#64;Overridepublic void run() {while (true) {}}}).start();}while(true){}}
}

由此可见&#xff0c;Java中的多线程是可以利用多核的&#xff0c;这是真正的多线程&#xff01;而Python中的多线程只能利用单核&#xff0c;这是假的多线程&#xff01;

 

三、解决方法

转&#xff1a;链接&#xff1a;https://www.zhihu.com/question/23474039/answer/269526476
就如此&#xff1f;我们没有办法在Python中利用多核&#xff1f;当然可以&#xff01;刚才的多进程算是一种解决方案&#xff0c;还有一种就是调用C语言的链接库。对所有面向I/O的&#xff08;会调用内建的操作系统C代码的&#xff09;程序来说&#xff0c;GIL会在这个I/O调用之前被释放&#xff0c;以允许其他线程在这个线程等待I/O的时候运行。我们可以把一些 计算密集型任务用C语言编写&#xff0c;然后把.so链接库内容加载到Python中&#xff0c;因为执行C代码&#xff0c;GIL锁会释放&#xff0c;这样一来&#xff0c;就可以做到每个核都跑一个线程的目的&#xff01;

可能有的小伙伴不太理解什么是计算密集型任务&#xff0c;什么是I/O密集型任务&#xff1f;

计算密集型任务的特点是要进行大量的计算&#xff0c;消耗CPU资源&#xff0c;比如计算圆周率、对视频进行高清解码等等&#xff0c;全靠CPU的运算能力。这种计算密集型任务虽然也可以用多任务完成&#xff0c;但是任务越多&#xff0c;花在任务切换的时间就越多&#xff0c;CPU执行任务的效率就越低&#xff0c;所以&#xff0c;要最高效地利用CPU&#xff0c;计算密集型任务同时进行的数量应当等于CPU的核心数。

计算密集型任务由于主要消耗CPU资源&#xff0c;因此&#xff0c;代码运行效率至关重要。Python这样的脚本语言运行效率很低&#xff0c;完全不适合计算密集型任务。对于计算密集型任务&#xff0c;最好用C语言编写。

第二种任务的类型是IO密集型&#xff0c;涉及到网络、磁盘IO的任务都是IO密集型任务&#xff0c;这类任务的特点是CPU消耗很少&#xff0c;任务的大部分时间都在等待IO操作完成&#xff08;因为IO的速度远远低于CPU和内存的速度&#xff09;。对于IO密集型任务&#xff0c;任务越多&#xff0c;CPU效率越高&#xff0c;但也有一个限度。常见的大部分任务都是IO密集型任务&#xff0c;比如Web应用。

IO密集型任务执行期间&#xff0c;99%的时间都花在IO上&#xff0c;花在CPU上的时间很少&#xff0c;因此&#xff0c;用运行速度极快的C语言替换用Python这样运行速度极低的脚本语言&#xff0c;完全无法提升运行效率。对于IO密集型任务&#xff0c;最合适的语言就是开发效率最高&#xff08;代码量最少&#xff09;的语言&#xff0c;脚本语言是首选&#xff0c;C语言最差。

综上&#xff0c;Python多线程相当于单核多线程&#xff0c;多线程有两个好处&#xff1a;CPU并行&#xff0c;IO并行&#xff0c;单核多线程相当于自断一臂。所以&#xff0c;在Python中&#xff0c;可以使用多线程&#xff0c;但不要指望能有效利用多核。如果一定要通过多线程利用多核&#xff0c;那只能通过C扩展来实现&#xff0c;不过这样就失去了Python简单易用的特点。不过&#xff0c;也不用过于担心&#xff0c;Python虽然不能利用多线程实现多核任务&#xff0c;但可以通过多进程实现多核任务。多个Python进程有各自独立的GIL锁&#xff0c;互不影响。

 

转:https://www.cnblogs.com/shmily2018/p/9123144.html



推荐阅读
  • 第七课主要内容:多进程多线程FIFO,LIFO,优先队列线程局部变量进程与线程的选择线程池异步IO概念及twisted案例股票数据抓取 ... [详细]
  • 云原生应用最佳开发实践之十二原则(12factor)
    目录简介一、基准代码二、依赖三、配置四、后端配置五、构建、发布、运行六、进程七、端口绑定八、并发九、易处理十、开发与线上环境等价十一、日志十二、进程管理当 ... [详细]
  • 开发笔记:Python之路第一篇:初识Python
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了Python之路第一篇:初识Python相关的知识,希望对你有一定的参考价值。Python简介& ... [详细]
  • 开发笔记:python协程的理解
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了python协程的理解相关的知识,希望对你有一定的参考价值。一、介绍什么是并发?并发的本质就是 ... [详细]
  • 本文介绍了在开发Android新闻App时,搭建本地服务器的步骤。通过使用XAMPP软件,可以一键式搭建起开发环境,包括Apache、MySQL、PHP、PERL。在本地服务器上新建数据库和表,并设置相应的属性。最后,给出了创建new表的SQL语句。这个教程适合初学者参考。 ... [详细]
  • Android中高级面试必知必会,积累总结
    本文介绍了Android中高级面试的必知必会内容,并总结了相关经验。文章指出,如今的Android市场对开发人员的要求更高,需要更专业的人才。同时,文章还给出了针对Android岗位的职责和要求,并提供了简历突出的建议。 ... [详细]
  • 本文介绍了如何使用php限制数据库插入的条数并显示每次插入数据库之间的数据数目,以及避免重复提交的方法。同时还介绍了如何限制某一个数据库用户的并发连接数,以及设置数据库的连接数和连接超时时间的方法。最后提供了一些关于浏览器在线用户数和数据库连接数量比例的参考值。 ... [详细]
  • t-io 2.0.0发布-法网天眼第一版的回顾和更新说明
    本文回顾了t-io 1.x版本的工程结构和性能数据,并介绍了t-io在码云上的成绩和用户反馈。同时,还提到了@openSeLi同学发布的t-io 30W长连接并发压力测试报告。最后,详细介绍了t-io 2.0.0版本的更新内容,包括更简洁的使用方式和内置的httpsession功能。 ... [详细]
  • 本文介绍了pack布局管理器在Perl/Tk中的使用方法及注意事项。通过调用pack()方法,可以控制部件在显示窗口中的位置和大小。同时,本文还提到了在使用pack布局管理器时,应注意将部件分组以便在水平和垂直方向上进行堆放。此外,还介绍了使用Frame部件或Toplevel部件来组织部件在窗口内的方法。最后,本文强调了在使用pack布局管理器时,应避免在中间切换到grid布局管理器,以免造成混乱。 ... [详细]
  • linux进阶50——无锁CAS
    1.概念比较并交换(compareandswap,CAS),是原⼦操作的⼀种,可⽤于在多线程编程中实现不被打断的数据交换操作࿰ ... [详细]
  • 深入理解线程、进程、多线程、线程池
    本文以QT的方式来走进线程池的应用、线程、进程、线程池、线程锁、互斥量、信号量、线程同步等的详解,一文让你小白变大神!为什么要使用多线程、线程锁、互斥量、信号量?为什么需要线程 ... [详细]
  • POCOCLibraies属于功能广泛、轻量级别的开源框架库,它拥有媲美Boost库的功能以及较小的体积广泛应用在物联网平台、工业自动化等领域。POCOCLibrai ... [详细]
  • ORACLE空间管理实验5:块管理之ASSM下高水位的影响
    数据库|mysql教程ORACLE,空间,管理,实验,ASSM,下高,水位,影响,数据库-mysql教程易语言黑客软件源码,vscode左侧搜索,ubuntu怎么看上一页,ecs搭 ... [详细]
  • Python 可视化 | Seaborn5 分钟入门 (六)——heatmap 热力图
    微信公众号:「Python读财」如有问题或建议,请公众号留言Seaborn是基于matplotlib的Python可视化库。它提供了一个高级界面来绘制有吸引力的统计图形。Seabo ... [详细]
  • 1、概述首先和大家一起回顾一下Java消息服务,在我之前的博客《Java消息队列-JMS概述》中,我为大家分析了:然后在另一篇博客《Java消息队列-ActiveMq实战》中 ... [详细]
author-avatar
crazyuzy327
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有