c#和python同一主机直接udp_为什么Python 如此之慢

f150cac9e31e78886563c63a3a9719d3.png

原文:

https://hackernoon.com/why-is-python-so-slow-e5074b6fe55b​hackernoon.com

Python 正在爆炸般流行起来,它被用于DevOps, 数据处理,web开发和安全领域。但是在速度方面却没有取得过什么胜利。
Java在速度方面和C/C++/C#/Python比起来如何?答案很大程度上取决于你所运行的应用。没有什么跑分是完美的,但是编程语言测评游戏(Computer Language Benchmarks Game)是一个很好的切入点。

十多年来编程语言测评游戏一直对我来说是一个参考,相比于其他语言,比如Java, C#, Go, JavaScript, C++, Python是最慢的语言之一。这些语言中包含了JIT编译器(c#, java),AOT编译器(c/c++)和解释型语言js。

注意: 当我说“Python”, 我说的是Python的参考实现CPython, 其他实现这篇文章也会提到。 这篇文章想要回答的一个问题就是:当Python执行一个相同的程序要比别的语言实现慢2-10倍的时候,为什么会这么慢,难道我们不能让它跑的更快吗?

下面说一下本文的主要观点(当然也是客观事实): "因为Python 有GIL(Global Interpreter Lock, 全局解释锁)" “因为Python 是解释型语言而不是编译型” “因为Python 是动态类型语言” 哪一个原因影响最大对速度影响最大呢?

GIL

现代计算机的cpu有多核,有时候有多个处理器。为了充分利用多出来的处理能力,操作系统定义了一种更加低级别的单位:线程,让一个进程可以启动多个线程来执行系统指令。 这样的话如果一个进程的CPU资源非常紧张,负载就会均匀的平摊到各个CPU核心,这种方法能够很高效地让大多数任务更快完成。 当我写这篇文章的时候,我的Chrome浏览器开启了44个线程。要记住的是线程的结构和api在POSIX-based的系统(OSX, Linux)和Windows下面是不一样的。操作系统同样会管理线程的调度。 如果你没有进行过多线程编程,你需要快速熟悉一下"锁"的概念。不像单线程的进程,多线程的进程中,当你更改内存中的变量,你需要确认多个线程不会同时尝试访问或修改同一个内存块。

当CPython创建变量,它会给变量分配内存空间并且计算变量的引用数,如果引用数为0, Python将会释放掉这块内存,这就是为什么for循环表达式里的临时变量不会让内存爆炸。也是CPython的垃圾回收机制。

接下来的挑战是,当变量被多个线程共享时,如何锁住引用数。Python程序执行过程中有一个全局解释锁GIL 小心地控制着线程的执行。Python解释器在同一时间只能执行一个操作,不论有多少个线程。

这对于Python应用的性能表现意味着什么呢?

如果你的应用是单线程单解释器的,这对你的应用性能毫无影响。移除GIL也不会对你的应用性能有任何影响。 如果你想在同一个解释器中使用线程进行并发操作,并且你的线程是IO密集型的,那你就会看到GIL的资源争夺。

David Beazley的博客中对多线程程序中 GIL 的作用进行了可视化:http://dabeaz.blogspot.com/2010/01/python-gil-visualized.html

下图表示了Python多线程程序中GIL的分配情况。

c47bd378491adabf5a679d53350e3238.png

如果一个Python程序里有多个线程,一个程序运行的时候会拿着GIL,当遇到I/O的时候会放开GIL,但是CPU-bound的线程通常不会进行I/O。Python切换线程的一种作法是每100 ticks检查一下,可以通过sys.setcheckinterval()修改这个数值。 综上所述,因为Python线程不能有效利用多核,但是增加了CPU context switch的消耗,所以对于CPU-bound的程序表现很差。更糟糕的是,在多核情况下可能表现会更差,因为系统支持多线程运行但是GIL保证只有一个线程运行,这时候多线程会反复的检查GIL是否被释放,但是拿不到GIL(因为有太多线程竞争),有可能导致系统发生Trashing现象。

如果你使用一个web应用(Django)并且使用WSGI,每个请求会有一个单独的Python解释器,由于Python的全局解释锁启动很慢,所以有的WSGI实现会有一个“守护模式”,就是先把Python进程启动起来放着,等待请求进来使用。

那其他的Python实现呢?

PyPy也有GIL但是比CPython快超过三倍。 JPython 没有GIL, 因为JPython的线程代表一个Java线程,得益于JVM的内存管理机制,JPython不使用GIL。

JavaScript是怎么做的呢

首先所有的Javascript 引擎使用标记-清除的垃圾回收机制。 上面提到过, GIL的需求主要是因为CPython的内存管理算法。 JavaScript 没有GIL, 但它同时也是单线程的所以它并不需要GIL。JavaScript使用事件循环和Promise/Callback实现异步的编程而不是使用并发。Python也有类似实现asyncio

“因为Python是解释型语言”

我经常听说这个言论,我觉得这是一个对于CPython执行方式的粗暴简化。 如果你在终端执行一个命令(比如python myscript.py),CPython会开始顺序执行一大串任务: 读取,词法分析,解析,编译,解释,执行代码。

一个重点是.pyc文件的创建。在编译阶段,字节码串被写到pycache/下(3.x)或者和py文件相同的文件夹(2.x)。这个操作不仅对你自己的代码有效,也包括所有你导入的模块。

所以大多数情况下,Python在本地解释和执行字节码,与之相比 Java 和 C#.NET:

Java 编译成一个“中间语言”,然后JVM读字节码实时将其转化为机器码,.NET的CIL也一样,.NET CLR(Common-Language-Runtime, 通用语言运行时),使用的是实时编译到机器码(JIT)。

所以,如果它们都用到了虚拟机和部分字节码,为什么Python在跑分上比Java/C#慢这么多呢?

Java/C# 是即时编译(JIT)的。
JIT要求一个中间语言,以便让代码转换成区块。AOT编译是为了可以在交互前保证CPU能理解每一行代码。
JIT本身不会让执行速度更快,以为它仍然是在执行相同的字节码, 然而JIT可以让实时优化成为可能,一个好的JIT编译器应用的那一部分被执行很多次,这些部分被称为“热点”。 这样编译器会将这些部分替换成更加高效的版本。这意味着如果你的程序重复做相同的事情,使用JIT就能显著提高速度。同时Java/C#是强类型的语言所以优化器可以对语言作出更多预设。

PyPy 使用JIT,前面提到,它比CPython快得多。

所以为什么CPython不用JIT呢

JIT有很多缺点,其中一个就是启动慢。

CPython 启动已经相对很慢了, PyPy比CPython启动慢CPython2-3倍。JVM启动是出了名的慢。.NET CLR使用随操作系统启动来解决这个问题, 但CLR的开发者同时也是其依赖的系统的开发者(win)。

如果你的Python是单进程,运行时间很长,并且有很多重复操作可以被优化,那么使用JIT就很有意义。 但是CPython是通用实现,当使用Python开发命令行工具,每次都等待JIT启动是非常糟糕的体验。 CPython需要服务于尽可能广泛的场景,有可能使用JIT反而会大幅度拖累系统性能。 如果你需要使用JIT并且有一个适合的工作场景,那可以使用PyPy。

“因为Python是动态类型语言”

在静态类型语言中,声明变量之前需要声明变量类型,包括 C, C++, Java, C#, Go。动态类型语言中仍然有类型的概念,但是变量的类型可变。

a 

这个小例子中, Python 使用相同的变量名创建了类型不同的第二个变量,释放掉了第一个变量的内存空间。
静态类型语言并不是为了麻烦你而设计的,而是根据CPU行为设计的。如果所有的行为最终会变成二进制操作,你必须将对象转换成更加底层的数据结构。

Python为你代劳了转换到底层数据结构这一步,所以你不用关心。当然不用声明变量并不是Python慢的原因。 Python语言的设计极为灵活,几乎所有东西都能变成动态的,比如猴子补丁。这种设计让Python的优化变得难以想象的困难。

猴子补丁: 1. 在运行时替换方法、属性等 2. 在不修改第三方代码的情况下增加原来不支持的功能 3. 在运行时为内存中的对象增加patch而不是在磁盘的源代码中增加

python中一个很简单的例子:

import 

所以是Python的动态性让它如此慢吗?

比较和转换类型非常耗费资源, 每次对变量读写、引用都需要检查类型。如此动态化的语言是很难优化的,很多Python的不同实现能更快是因为为了性能在灵活性方面做了妥协。

比如CPython, 将C语言的静态类型和Python结合,这些静态类型能提供84倍的性能优化。

结论

Python这么慢主要是因为动态的生态和它的多功能性。它能用来解决所有类型的问题,所以在不同领域我们可以选择更加快速的Python版本。
有很多方法可以用来优化你的Python程序,比如活用async, 了解分析工具, 考虑使用多个解释器等等。比如一些启动时间不重要的应用,或者能够能JIT获益的程序我们可以使用PyPy。如果你的代码有些部分非常要求性能,又使用了很多C语言的静态类型,那么选择Cython。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/262087.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

lldb 调试php,linux系统下如何在vscode中调试C++代码

本篇博客以一个简单的hello world程序,介绍在vscode中调试C代码的配置过程。1. 安装编译器vscode是一个轻量的代码编辑器,并不具备代码编译功能,代码编译需要交给编译器完成。linux下最常用的编译器是gcc,通过如下命令安装&#x…

php负责传递数据,php传递数据的方法有哪些

php传递数据的方法有哪些发布时间:2021-03-19 09:10:54来源:亿速云阅读:58作者:小新这篇文章将为大家详细讲解有关php传递数据的方法有哪些,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅…

除了工作怎么交朋友_夫妻感情不好怎么办?夫妻关系紧张该如何解决?

夫妻感情不好怎么办?夫妻关系紧张该如何解决?1. 象征两人的兴趣随着年龄的增长而多样化。年轻的时候往往因为他们之间的差异而互相吸引,但当他们在中老年则需要更多的安慰或关心,理解,需求就不同了。当你发现自己的志向迥然不同时…

java websocket修改为同步_服务端向客户端推送消息技术之websocket的介绍

websocket的介绍在讲解WebSocket前,我们先来看看下面这种场景,在HTTP协议下,怎么实现。需求:在网站中,要实现简单的聊天,这种情况怎么实现呢?如下图:​当发送私信的时候,…

python random randint_python中random.randint和random.randrange的区别详解

在python中,通过导入random库,就能使用randint 和 randrange 这两个方法来产生随机整数。那这两个方法的区别在于什么地方呢?让我们一起来看看! 区别: randint 产生的随机数区间是包含左右极限的,也就是说左右都是闭区…

How to change max_allowed_packet size

2019独角兽企业重金招聘Python工程师标准>>> How to change max_allowed_packet size up vote 116 down vote favorite 40I am having a problem with BLOB fields in my MySQL database - when uploading files larger than approx 1M…

.net runtime占用cpu_.net 中的StringBuilder和TextWriter区别

最近闲来之余,看了一些开源的类库,看到有些类库喜欢用TextWriter类来记录相关的字符串数据,感到比较好奇,为啥不用StringBuilder类对象。于是在网上搜索了一番,总结了相关笔记。StringBuilder类在 .net 中,字符串作为一…

微信页面弹出窗口,底部不随窗口滑动而滚动

公司是做微信第三方公众平台,有一个购物系统,现在需要将商品页面模仿淘宝的样式,就是点击购物车或购买按钮,会弹出一个窗口,显示sku和数量。本来就是一个做java后台的,前端布局不是很懂,上网搜索…

【GIT】使用Git命令窗口将本地工程提交至远程GitHub

目标: 1.解决的问题是如何通过Git命令窗口将本地工程提交至GitHub。 2.方便园友的同时也方便自己以后解决此类问题。 步骤: 1.首先登陆GitHub网站https://github.com/ 2.新建Repository 3.新建TicketBrushSystem的Repository,其中红框的几处可…

softmax ce loss_手写softmax和cross entropy

import 解释下给定的数据,x假设是fc layer的输出,可以看到这里x是(3,3)的,也就是batch_size3,n_classes3。但是label给出了三个数,取值是0,1,因此这里必须要将label先变成one_hot的形式才能在cr…

kafka php 0.8,php5.6 centos7 kafka0.8.1

# 首先在保证php已经正确安装的情况下:# 安装jdk(本人安装jdk7) 和 scala 因为kafka基于scala开发# 之后解压安装包 进入 运行命令 ./gradlew jar # 会下载一些包 # 首先运行 zookeeper ./bin/zookeeper-server-start.sh ./config/zookeeper.properties# 之后运行k…

day02(下)_运算符

首先了解java运算符的优先级和结合性: 常用转义字符表: 示例1 取余/字符串/转义字符: class operator1 {public static void main(String[] args){//取余System.out.println(-1%5);//-1System.out.println(1%-5);//1与左边的操作数同号System.out.println(3.1%2.5);//字符串:字…

activity 生命周期_如何理解安卓activity的生命周期(on-create篇)?

个人认为用类比的方式来学习新事物比较容易接受。我这里用蝴蝶的一生来做比喻。OnCreate阶段就像是蝴蝶的幼虫刚出卵里孵化出来,蝴蝶的一生只可能出生一次,oncreate只能被创建一次。蝴蝶刚出生的时候还不是蝴蝶,而是一只毛毛虫一样的东西&…

【十大经典数据挖掘算法】k-means

【十大经典数据挖掘算法】系列 C4.5K-MeansSVMAprioriEMPageRankAdaBoostkNNNave BayesCART1. 引言 k-means与kNN虽然都是以k打头,但却是两类算法——kNN为监督学习中的分类算法,而k-means则是非监督学习中的聚类算法;二者相同之处&#xff1…

ajax获取数据用弹窗显示_Vue之 点击返回弹出推荐商品弹窗

阅读本文约需要5分钟大家好,我是你们的导师,我每天都会在这里给大家分享一些干货内容(当然了,周末也要允许老师休息一下哈)。上次老师跟大家分享了VUE 之 v-on指令的知识,今天跟大家分享下Vue之 点击返回弹出推荐商品弹窗的知识。…

Navicat 编辑器自动完成代码功能讲解

2019独角兽企业重金招聘Python工程师标准>>> Navicat 提供广泛的编辑器高级功能,例如:编辑代码功能、智能自动完成代码、设置 SQL 格式及更多。本教程将介绍关于自动完成代码的操作。 Navicat下载地址:http://www.formysql.com/xi…

com 组件调用不起来_AwesomeGithub组件化探索之旅

阅读前请点击右上角“关注”,每天免费获取Android知识解析及面试解答。Android架构解析,只做职场干货,完全免费分享!之前一直听说过组件化开发,而且面试也有这方面的提问,但都未曾有涉及具体的项目。所以就…

将团队迁移到可视化项目管理软件

自2000年代中期,“Scrum”项目管理(PM)一直统治着软件开发方法。它的迭代结构、频繁会议和清晰的层次结构使其成为受频繁变化的客户需求和条件管制的行业的明显选择。因此,大多数团队习惯基于 Scrum项目管理应用管理开发过程。 \\…

一步一步学Silverlight 2系列(3):界面布局_转载

概述 Silverlight 2 Beta 1版本发布了,无论从Runtime还是Tools都给我们带来了很多的惊喜,如支持框架语言Visual Basic, Visual C#, IronRuby, Ironpython,对JSON、Web Service、WCF以及Sockets的支持等一系列新的特性。《一步一步学Silverlig…

b树与b+树的区别_一文详解 B-树,B+树,B*树

B-树B-树是一种多路搜索树(并不一定是二叉的)1970年,R.Bayer和E.mccreight提出了一种适用于外查找的树,它是一种平衡的多叉树,称为B树(或B-树、B_树)。一棵m阶B树(balanced tree of order m)是一…