python单核运行_python下多核,单核CPU对于并行,并发执行效率的对比-Go语言中文社区...
**
**
这篇博客主要内容为python 中多线程以及多进程的效率对比,以及记录自己在做这个实验中遇到的一些问题以及心得
背景引入:
CPU制造商为了追求CPU效率放弃了在CPU频率上的追求(CPU频率即CPU单位时间内可以完成任务的多少),反而开始把方向转向了多核CPU上。那么如何在多核CPU上充分发挥出多核的优势就成了一个问题。
首先是简单介绍下多线程与多进程:
线程:
是程序执行流的最小单元,是系统独立调度和分配CPU(独立运行)的基本单位。线程(有时被称为轻量级进程)跟进程有些相似,不同的是,所有的线程运行在同一个进程中, 共享相同的运行环境。它们可以想像成是在主进程或“主线程”中并行运行的“迷你进程”。
进程:
是资源分配的基本单位。一个进程包括多个线程。进程(有时被称为重量级进程)是程序的一次 执行。每个进程都有自己的地址空间,内存,数据栈以及其它记录其运行轨迹的辅助数据。操作系 统管理在其上运行的所有进程,并为这些进程公平地分配时间。进程也可以通过 fork 和 spawn 操作 来完成其它的任务。不过各个进程有自己的内存空间,数据栈等,所以只能使用进程间通讯(IPC), 而不能直接共享信息。
说简单点进程就好比QQ,浏览器这些应用程序,而线程就像QQ里和不同的人的聊天窗口或者浏览器中播放的音乐,显示的网页。
区别:
1.线程与资源分配无关,它属于某一个进程,并与进程内的其他线程一起共享进程的资源。
2.每个进程都有自己一套独立的资源(数据),供其内的所有线程共享。
3.不论是大小,开销线程要更“轻量级”
4.一个进程内的线程通信比进程之间的通信更快速,有效。(因为共享变量)
测试机:
物理机
虚拟机操作系统
macOS
Ubuntu16.04
CPU
双核
单核
内存
8G
2G
python在管理多线程使用了GIL
pythonGIL解释:
GIL是实现python解释器时引入的一个概念,像C语言一样,python 的解释器也有很多,常见的有CPython,Psyco,PyPy。 而GIL是实现CPyhon时引入的。
In CPython, the global interpreter lock, or GIL, is a mutex that prevents multiple native threads from executing Python bytecodes at once. This lock is necessary mainly because CPython’s memory management is not thread-safe. (However, since the GIL exists, other features have grown to depend on the guarantees that it enforces.)
GIL的出现是有历史原因的,对于并行和并发这样的多任务,就是为了提高CPU的使用效率,然而需要注意的是,一个CPU一个时间只能实现一个任务,也就是说一个CPU永远不可能并行的,但是可以借助CPU轮训制度频繁切换任务,完成多任务。
python在刚创立的时候只考虑到了单核CPU,那么考虑到多线程的数据完整性以及状态同步就需要加一把大锁,所以呢,GIL应运而生。
GIL说简单点就是一把大锁,一把有很大权力的锁,一把可以控制CPU的锁,它可以保证一个时间内只能有一个CPU在工作,确保了多线程数据完整性和状态同步,看到这个地方,大家就有疑惑了,那还要多核CPU干什么,都成单核的了。这也确实是GIL局限性的地方。从上面的英文解释中可以看出GIL可
+以保证线程的安全,刚看到这个概念我有点疑惑,难道操作系统自身的线程调度机制不可以吗,通过查找操作系统的资料我发现,操作系统还真的不可以,下面介绍几种调度算法;
1、先到先服务调度算法(FCFS)
根据就绪队列的到达时间来服务,此时就绪队列是一个FIFO队列,先到先服务,后到的线程不能抢占前面正在服务的线程。这种算法的优点是实现简单,缺点也很明显,就是CPU进程区间变化很大时,平均等待时间会变化很大。
2、最短作业优先调度(SJF)
顾名思义,就是CPU进程区间最短的先执行,如果两个进程区间具有同样的长度,那么按照FCFS来调度。
SJF可以是抢占的,也可以是不抢占的。它的平均等待时间优于FCFS。
3、优先级调度
其实上面的SJF算法就是一种特殊的优先级调度,只不过这里的优先级定义更加广泛一些,SJF算法的优先级是按照CPU进程区间长短来定义的,这里的优先级可以是其他的一些定义。
优先级调度可以是抢占的,也可以是非抢占的。
优先级调度的一个主要问题是无穷阻塞(也称为饥饿),如果一个线程的优先级很低,可能需要等待很长的时间才能到这个线程执行,甚至永远不执行,一种解决方法是老化(随着时间的增长,增加线程的优先级)
4、轮转法调度(RR)
轮转法调度专门是为分时系统设计的。它类似于FCFS,但是增加了抢占为了切换线程。定义一个较小的时间单元,称为时间片,通常为10-100ms。为了实现RR算法,将就绪队列保存为FIFO队列,新进程增加到就绪队列队尾,CPU调度程序从就绪队列选择第一个进程,设置定时器在一个时间片之后再中断,再分派这个进程。
如果该进程的CPU区间小于时间片,进程本身就会释放CPU,调度程序继续处理下一个进程,如果当前进程的CPU区间比时间片长,定时器会产生CPU中断,实行上下文切换,然后将此进程放到就绪队列队尾,继续调度就绪队列第一个进程。
可以看出计算机并不知道代码的具体含义,所以如果代码只是使用数据就没有问题,如果代码要改变数据可能会导致再多线程时数据不同步状态不统一,所以GIL这把锁就可以保证线程的安全。正如上文所说,GIL也确实是一个缺陷无法充分体现出多核的优势,那么我们应该避免这个问题呢:
1.用其他解析器
之前也提到了既然GIL只是CPython的产物,那么其他解析器是不是更好呢?没错,像JPython这样的解析器由于实现语言的特性,他们不需要GIL的帮助。然而由于用了Java/C#用于解析器实现,他们也失去了利用社区众多C语言模块有用特性的机会。所以这些解析器也因此一直都比较小众。所以这个方法并不推荐
2.使用多进程代替多线程
用multiprocessing替代Thread
multiprocessing库的出现很大程度上是为了弥补thread库因为GIL而低效的缺陷。它完整的复制了一套thread所提供的接口方便迁移。唯一的不同就是它使用了多进程而不是多线程。每个进程有自己的独立的GIL,因此也不会出现进程之间的GIL争抢。当然multiprocessing也不是万能良药。它的引入会增加程序实现时线程间数据通讯和同步的困难。multiprocessing由于进程之间无法看到对方的数据,只能通过在主线程申明一个Queue,put再get或者用share memory的方法。这个额外的实现成本使得本来就非常痛苦的多线程程序编码,变得更加痛苦了。但是这仍然是我觉得对于初学者来说最友好的方法了。
代码实现
python中关于线程的使用涉及到threading模块,进程使用涉及multiprocessing模块
都只是使用最基本的start,len方法,所以这里不多赘述。
直接上代码:
需要的第三方库
import requests
import time
import threading
from multiprocessing import Process
首先是线性执行CPU密集型函数,IO密集型函数
# 定义CPU密集型函数
def count(x, y):
c = 0
while c < 500000:
c += 1
x += x
y += y
#定义IO密集型函数
def write():
f = open("test.txt", "w")
for x in range(500000):
f.write("testwriten")
f.close()
def read():
f = open("test.txt", "r")
lines = f.readlines()
f.close()
#定义网络请求函数
head_request = {
'User-Agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36'
}
url = "http://www.tieba.com"
def http_request():
try:
res = requests.get(url, headers=head_request)
html = res.text
return {"context": html}
except Exception as e:
return {"error": e}
# CPU密集操作
t = time.time()
for x in range(10):
count(1, 1)
print("cpu函数运行时间:", time.time() - t)
# IO密集操作
t = time.time()
for x in range(10):
write()
read()
print("IO函数运行时间:", time.time() - t)
接下来是多线程并发模拟CPU密集型函数`
# 定义CPU密集型函数
def count(x, y):
c = 0
while c < 500000:
c += 1
x += x
y += y
counts = []
t = time.time()
for x in range(10):
thread = threading.Thread(target=count, args=(1,1))
counts.append(thread)
thread.start()
e = counts.__len__() #这里使用了一个魔术方法,获取counts的长度
while True:
for i in counts:
if not i.is_alive():
e -= 1
if e <= 0:
break # 当所有线程执行完毕后退出
print(time.time() - t)
多进程模拟CPU密集型函数
# 定义CPU密集型函数
def count(x, y):
c = 0
while c < 500000:
c += 1
x += x
y += y
counts = []
t = time.time()
for x in range(10):
process = Process(target=count, args=(1,1))
counts.append(process)
process.start()
e = counts.__len__()
while True:
for i in counts:
if not i.is_alive():
e -= 1
if e <= 0:
break
print(time.time() - t)
物理机
虚拟机线性执行CPU密集型函数
65.29
120
线性执行IO密集型函数
1.76
1.6
多线程并发模拟CPU密集型函数
65.92
132.58
多进程并行模拟CPU密集型函数
38.87
127.9
通过上面的表格进行数据对比,明显发现在多核的情况下,python的多进程要比多线程快得多。那么是为什么呢,这里就要说到python的多线程管理机制,在python3.x中,GIL使用计时器(执行时间达到阈值后,当前线程释放GIL)对线程进行管理,这样对CPU密集型程序更加友好,但依然没有解决GIL导致的同一时间只能执行一个线程的问题,所以效率依然不尽如人意。而且在多核的情况下可能在进程调度轮训的过程中还会产生CPU的竞争会产生更加坏的效果。
#GIL即全局解释器锁
然而对于IO密集型函数或者网络请求函数,多线程就是友好地,因为可以利用函数的挂起空闲时间进行线程的转换,充分利用到了多核CPU的优势。
在单核的情况下,模拟的多进程并行的效率也是优于多线程并发的。
Liunx多线程pthread初探:https://blog.csdn.net/xuanandting/article/details/78842795
python单核运行_python下多核,单核CPU对于并行,并发执行效率的对比-Go语言中文社区...相关推荐
- python turtle 椭圆_Python易学就会(五)turtle绘制椭圆与递归-Go语言中文社区
前两篇文章基本涵盖了turtle的大部分功能,同时也借由对turtle功能的展示,厘清了Python的一些语法特点,以利于新手入门.但是短短几个例子,阐述得还是有限,这里再展开两个知识点,一方面对tu ...
- python 图灵 微信 菜谱_python——wxpy模块实现微信尬聊(基于图灵机器人)-Go语言中文社区...
wxpy(微信机器人)是在itchat基础上开发的微信个人功能服务API,基本可以实现微信各种拓展功能, 支持pip安装,适用2.7以及3.4-3.6的python版本 通过# 导入模块 from w ...
- python爬取天气数据山东_Python爬取天气预报数据,并存入到本地EXCEL中-Go语言中文社区...
近期忙里偷闲,搞了几天python爬虫,基本可以实现常规网络数据的爬取,比如糗事百科.豆瓣影评.NBA数据.股票数据.天气预报等的爬取,整体过程其实比较简单,有一些HTML+CSS+DOM树等知识就很 ...
- linux连接wpa wifi密码,Linux环境下使用WIFI模块:使用wpa_supplicant工具配置和连接WIFI-Go语言中文社区...
使用wpa_supplicant工具配置和连接WIFI 实验版本及下载地址 wpa_supplicant:wpa_supplicant-2.7 链接: [http://w1.fi/wpa_suppli ...
- mysql php7安装配置_centos7无网络下安装部署php7.1.33+mysql5.7.28+apache2.4.6-Go语言中文社区...
centos7无网络下安装部署php7.1.33+mysql5.7.28+apache2.4.6 一. 1.先ping www.baidu.com,root账户下,如果未联网,创建目录,把提前下载好的 ...
- linux wc read,Linux 下使用 wc 统计文件夹下所有文件的代码行数(包括子目录)-Go语言中文社区...
wc 命令用于统计文件内容的行数.单词数.字母数. 但是如果想统计一个目录下所有文件的行数,wc 并没有提供递归统计. 不过,可以结合 find 命令,例如: $ wc -l `find -name ...
- linux下的go富集分析,GO富集分析(转载)-Go语言中文社区
GO富集介绍 每个基因都会对应有一个或多个GO term(也就是GO功能). 富集涉及到两个概念:前景基因和背景基因.前景基因就是你关注的要重点研究的基因集,背景基因就是所有的基因集.比如做两个样本对 ...
- python10以内的加减计算器_python学习之实现简单计算器(加减乘除)小学生能力测试-Go语言中文社区...
1.小学生算术能力测试系统: 题目要求: 设计一个程序,用来实现帮助小学生进行百以内的算术练习,它具有以下功能: 提供10道加.减.乘或除四种基本算术运算的题目: 练习者根据显示的题目输入自己的答案, ...
- python逐行运行_python逐行执行
广告关闭 腾讯云11.11云上盛惠 ,精选热门产品助力上云,云服务器首年88元起,买的越多返的越多,最高返5000元! 我已经编写了一些代码来尝试执行以下操作 我之前在python代码中检索过的ope ...
最新文章
- 元学习(meta learning) 最新进展综述论文,28页pdf
- java项目集成mybatis_JAVA应用程序单独集成Mybatis使用Demo
- 3.MATLAB界面介绍
- 极速生成缩略图,Serverless 支撑赛事转播锁定冬奥亮点
- 每个人都应该知道的25个大数据术语 1
- 如何进入python程序代码编辑环境_Python怎么打开代码编辑器 来学习吧
- python开发web运维工具_Python web 开发工具箱
- Nginx HTTP之请求行解析函数ngx_http_parse_request_line
- 【Python3网络爬虫开发实战】1.7.2-mitmproxy的安装
- 网易身患绝症员工被裁事件背后 年轻一代的辛酸和压力
- assert:python断言报错语句
- UIImageJPEGRepresentation 使用中存在的问题
- 在ubuntu用wine安装微信 并解决无法输入文字的问题 ubuntu完美安装微信
- Notes Twenty-third days-渗透攻击-红队-红队自研
- 计算机网络ping超时,ping请求超时怎么回事?ping请求超时的解决方法
- 华为数通笔记-BGP选路与负载分担
- Robot framework模拟打开浏览器问题
- 计算机一级考试模拟题2003word,2015计算机一级MsOffice练习:Word2003
- 编译安装zabbix时遇到configure: error: no acceptable C compiler found in $PATH 问题解决
- python 仪表数字识别,利用Python进行数字识别