澳门至尊网站-首页

您的位置:澳门至尊网站 > 黑客安全 > Python发展介绍,为什么Python为这么慢

Python发展介绍,为什么Python为这么慢

2019-11-21 23:31

Python语言 近年来 人气爆棚 。它广泛应用于网络开发运营,数据科学,网络开发,以及网络安全问题中。

一、            Python主要应用领域

然而, Python 在速度上完全没有优势可言。

(1)       云计算

在速度上,Java如何同C,C++,C#或者Python相比较?答案几乎完全取决于要运行的应用。在这个问题上,没有完美的评判标准,然而The Computer Language Benchmarks Game 是一个不错的方法。

(2)       WEB开发

链接:

(3)       科学计算、人工智能

(4)       系统运维

基于我对The Computer Language Benchmarks Game超过十年的观察,相比于Java,C#,Go,JavaScript, C++等,Python是最慢的语言之一。其中包括了 JIT (C#, Java) 和 AOT (C, C++)编译器,以及解释型语言,例如JavaScript。

(5)       金融

动态编译:

(6)       图形GUI

二、            Python在一些公司的应用

静态编译:

(1)       谷歌

(2)       CIA

注意:当我提到“Python”时,我指的是CPython这个官方的解释器。我也将在本文中提及其他的解释器。

(3)       NASA

我想要回答这样一个问题:当运行同一个程序时,为什么Python会 比其他语言慢2到10倍?为什么我们无法将它变得更快?

(4)       YouTube

以下是最主要的原因:

(5)       Dropbox

  • “它是GIL(Global Interpreter Lock全局解释器锁)”
  • “它是解释型语言而非编译语言”
  • “它是动态类型语言”

(6)       Instagram

那么以上哪种原因对性能影响最大呢?

(7)       Facebook

“它是全局解释器锁”

(8)       Redhat

现代计算机的CPU通常是多核的,并且有些拥有多个处理器。为了充分利用多余的处理能力,操作系统定义了一种低级的结构叫做线程:一个进程(例如Chrome浏览器)可以产生多个线程并且指导内部系统。

(9)       豆瓣

如果一个进程是CPU密集型,那么其负载可以被多核同时处理,从而有效提高大多数应用的速度。

(10)   知乎

当我写这篇文章时,我的Chrome浏览器同时拥有44个线程。注意,基于POSIX(比如MacOS和Linux)和Windows操作系统相比,线程的结构和API是不同的。操作系统也会处理线程的调度问题。

(11)   春雨医生

如果你之前没有做过多线程编程,你需要快速熟悉锁的概念。区别于单线程进程,你需要确保当内存中的变量被修改时,多线程不会同时试图访问或者改变同一个存储地址。

(12)   等等

当CPython创建变量时,它会预先分配存储空间,然后计算当前变量的引用数目。这个概念被称为引用计数。如果引用计数为零,那么它将从系统中释放对应存储区域。

三、            Python

这就是为什么在CPython中创造“临时”变量不会使应用占用大量的存储空间——尤其是当应用中使用了for循环这一类可能大量创建“临时”变量的结构时。

python动态语言,强类型语言

当存在多个线程调用变量时,CPython如何锁住引用计数成为了一个挑战。而“全局解释锁”应运而生,它能够谨慎控制线程的执行。无论有多少的线程,解释器每次只能执行一个操作。

(一)    优点

这对Python的性能意味着什么呢?

(1)           Python的定位是“优雅”、“明确”、“简单”,所以Python程序看上去总是简单易懂,初学者学Python,不但入门容易,而且将来深入下去,可以编写那些非常非常复杂的程序。

如果你的应用基于单线程、单解释器,那么讨论速度这一点就毫无意义,因为去掉GIL并不会影响代码性能。

(2)           开发效率非常高,Python有非常强大的第三方库,基本上你想通过计算机实现任何功能,Python官方库里都有相应的模块进行支持,直接下载调用后,在基础库的基础上再进行开发,大大降低开发周期,避免重复造轮子。

如果你想使用线程在单解释器(Python 进程)中实现并发,并且你的线程为IO密集型(例如网络IO或磁盘IO),你就会看到GIL争用的结果。

(3)           高级语言——当你用Python语言编写程序的时候,你无需考虑诸如如何管理你的程序使用的内存一类的底层细节

如果你有一个网络应用(例如Django)并且使用WSGI,那么每一个对于你的网络应用的请求将是一个独立的Python解释器,因此每个请求只有一个锁。因为Python解释器启动很慢,一些WSGI便集成了能够使保持Python进程的“守护进程”  。

(4)           可移植性——由于它的开源本质,Python已经被移植在许多平台上(经过改动使它能够工 作在不同平台上)。如果你小心地避免使用依赖于系统的特性,那么你的所有Python程序无需修改就几乎可以在市场上所有的系统平台上运行

那么其他Python解释器的速度又如何呢?

(5)           可扩展性——如果你需要你的一段关键代码运行得更快或者希望某些算法不公开,你可以把你的部分程序用C或C++编写,然后在你的Python程序中使用它们。

PyPy拥有GIL,通常比CPython快至少三倍。

(6)           可嵌入性——你可以把Python嵌入你的C/C++程序,从而向你的程序用户提供脚本功能。

Jython没有GIL,因为在Jython中Python线程是用Java线程表示的,这得益于JVM内存管理系统。

(二)    缺点:

JavaScript是如何做到这一点的呢?

(1)           速度慢,Python 的运行速度相比C语言确实慢很多,跟JAVA相比也要慢一些,因此这也是很多所谓的大牛不屑于使用Python的主要原因,但其实这里所指的运行速度慢在大多数情况下用户是无法直接感知到的,必须借助测试工具才能体现出来,比如你用C运一个程序花了0.01s,用Python是0.1s,这样C语言直接比Python快了10倍,算是非常夸张了,但是你是无法直接通过肉眼感知的,因为一个正常人所能感知的时间最小单位是0.15-0.4s左右,哈哈。其实在大多数情况下Python已经完全可以满足你对程序速度的要求,除非你要写对速度要求极高的搜索引擎等,这种情况下,当然还是建议你用C去实现的。

首先,所有的Javascript引擎使用标记加清除的垃圾收集系统,而之前提到GIL的基本诉求是CPython的存储管理算法。

(2)           代码不能加密,因为PYTHON是解释性语言,它的源码都是以名文形式存放的,不过我不认为这算是一个缺点,如果你的项目要求源代码必须是加密的,那你一开始就不应该用Python来去实现。

JavaScript没有GIL,但因为它是单线程的,所以也并不需要GIL。

(3)           线程不能利用多CPU问题,这是Python被人诟病最多的一个缺点,GIL即全局解释器锁(Global Interpreter Lock),是计算机程序设计语言解释器用于同步线程的工具,使得任何时刻仅有一个线程在执行,Python的线程是操作系统的原生线程。在Linux上为pthread,在Windows上为Win thread,完全由操作系统调度线程的执行。一个python解释器进程内有一条主线程,以及多条用户程序的执行线程。即使在多核CPU平台上,由于GIL的存在,所以禁止多线程的并行执行。关于这个问题的折衷解决方法,我们在以后线程和进程章节里再进行详细探讨。

JavaScript通过事件循环和承诺/回调模式来实现异步编程的并发。Python有与异步事件循环相似的过程。

(三)       Python解释器

 “因为它是解释型语言”

(1)           CPython

 

当我们从Python官方网站下载并安装好Python 2.7后,我们就直接获得了一个官方版本的解释器:CPython。这个解释器是用C语言开发的,所以叫CPython。在命令行下运行python就是启动CPython解释器。

我经常听到这句话。我觉得这只是对于CPython实际运行方式的一种简单解释。如果你在终端中输入python myscript.py,那么CPython将对这段代码开始一系列的读取,词法分析,解析,编译,解释和运行。

CPython是使用最广的Python解释器。教程的所有代码也都在CPython下执行。

这个过程中的重要步骤是在编译阶段创建一个.pyc 文件,这个字节码序列将被写入Python3下__pycache__/ 路径中的一个文件(对于Python2,文件路径相同)。这个步骤不仅仅应用于脚本文件,也应用于所有导入的代码,包括第三方模块。

(2)           IPython

所以大多时候(除非你写的代码只运行一次),Python是在解释字节码并且本地执行。下面我们将Java和C#.NET相比较:

IPython是基于CPython之上的一个交互式解释器,也就是说,IPython只是在交互方式上有所增强,但是执行Python代码的功能和CPython是完全一样的。好比很多国产浏览器虽然外观不同,但内核其实都是调用了IE。

Java编译成一门“中间语言”,然后Java虚拟机读取字节代码并即时编译为机器代码。.NET的通用中间语言(CIL)是一样的,它的通用语言运行时间(CLR)也采用即时编译的方法转化为机器代码。

CPython用>>>作为提示符,而IPython用In [序号]:作为提示符。

那么,如果Python用的是和Java和C#一样的虚拟机和某种字节代码,为什么在基准测试中它却慢得多?首先,.NET和Java是采用JIT编译的。

(3)           PyPy

JIT,又称即时编译,需要一种中间语言来把代码进行分块(或者叫数据帧)。预编译(AOT, Ahead of Time)器的设计保证了CPU能够在交互之前理解代码中的每一行。

PyPy是另一个Python解释器,它的目标是执行速度。PyPy采用JIT技术,对Python代码进行动态编译(注意不是解释),所以可以显著提高Python代码的执行速度。

JIT本身不会使执行速度更快,因为它仍然执行相同的字节码序列。但是,JIT允许在运行时进行优化。好的JIT优化器可以检测哪些部分执行次数比较多,这些部分被称为“热点”。然后,它将用更高效的代码替换它们,完成优化。

绝大部分Python代码都可以在PyPy下运行,但是PyPy和CPython有一些是不同的,这就导致相同的Python代码在两种解释器下执行可能会有不同的结果。如果你的代码要放到PyPy下执行,就需要了解PyPy和CPython的不同点。

这就意味着当计算机应用程序需要重复做一件事情的时候,它就会更加地快。另外,我们要知道Java和C#是强类型语言(变量需要预定义),因此优化器可以对代码做更多的假设。

(4)           Jython

PyPy使用即时编译器,并且前文也有提到它比CPython更快。这篇关于基准测试的文章介绍得更为详细——什么版本的Python最快?

Jython是运行在Java平台上的Python解释器,可以直接把Python代码编译成Java字节码执行。

链接:

(5)           IronPython

IronPython和Jython类似,只不过IronPython是运行在微软.Net平台上的Python解释器,可以直接把Python代码编译成.Net的字节码。

那么,为什么CPython不使用即时编译器呢?

Python的解释器很多,但使用最广泛的还是CPython。如果要和Java或.Net平台交互,最好的办法不是用Jython或IronPython,而是通过网络调用来交互,确保各程序之间的独立性。

JIT存在一些缺点:其中一个是启动时间。CPython启动时间已经相对较慢,PyPy比CPython还要慢2-3倍。众所周知,Java虚拟机的启动速度很慢。为了解决这个问题,.NET CLR在系统启动的时候就开始运行,但CLR的开发人员还开发了专门运行CLR的操作系统来加快它。

ps:部分内容摘自【金角大王等唐僧的日子】的随笔

如果你有一个运行时间很长的Python进程,并且其代码可以被优化(因为它包含前文所述的“热点”),那么JIT就能够起到很大作用。

但是,CPython适用于各类应用。因此,如果你使用Python开发命令行应用程序,每次调用CLI时都必须等待JIT启动,这将非常缓慢。

CPython必须尽量多地尝试不同的案例以保证通用性,而把JIT插入到CPython中可能会让这个项目停滞不前。

如果你想要借助JIT的力量,而且你的工作量还比较大,那么使用PyPy吧。

“因为它是一个动态类型语言”

 

在静态类型语言中,定义变量时必须声明类型。C, C++, Java, C#, Go都是这种语言。

在动态类型语言中,类型的概念依旧存在,但是这个变量的类型是动态变化的。

a = 1

a = “foo”

在上面这个例子中,Python创建第二个变量的时候用了同样的名字,但是变量类型是str(字符型),这样就对先前在内存中给a分配的空间进行了释放和再分配。

静态类型语言的这种设计并不是为了麻烦大家——它们是按照CPU的运行方式设计的。如果最终需要将所有内容都转化为简单的二进制操作,那就必须将对象和类型转换为低级数据结构。

Python自动完成了这个过程,我们看不见,也没必要看见。

不必声明类型不是使Python变慢的原因。Python语言的设计使我们几乎可以创建任何动态变量。我们可以在运行时替换对象中的方法,也可以胡乱地把低级系统调用赋给一个值。几乎怎么修改都可以。

正是这种设计使得优化Python变得异常困难。

为了阐明我的观点,我将使用一个MacOS中的应用。它是一个名为Dtrace的系统调用跟踪工具。CPython发行版没有内置DTrace,因此你必须重新编译CPython。以下演示中使用3.6.6版本。

wget

unzip v3.6.6.zip

cd v3.6.6

./configure –with-dtrace

make

现在python.exe将在整条代码中使用Dtrace跟踪器。Paul Ross就Dtrace做了一篇很棒的短演讲。 你可以下载Python的DTrace启动文件来测试函数调用、执行时间、CPU时间、系统调用等各种有意思的事情。例如:

sudo dtrace -s toolkit/<tracer>.d -c ‘../cpython/python.exe script.py’

DTrace启动文件:

演讲链接:

py_callflow跟踪器显示应用程序中的所有函数调用

因此,是Python的动态类型让它变慢的吗?

  • 比较和转换类型是耗时的,因为每次读取、写入变量或引用变量类型时都会进行检查
  • 很难优化一种如此动态的语言。其他语言之所以那么快是因为他们牺牲了一定的灵活性,从而提高了性能。
  • 了解一下Cython,它结合了C-Static类型和Python来优化已知类型的代码,可以提供84倍速度的性能提升。

结论

 

Python的缓慢主要是由于它动态和多用途的特点。它可以用于解决几乎所有问题,但是更加优化而快捷的替代方案可能存在。

但是,有一些方法可以通过利用异步计算,理解分析工具,以及考虑使用多个解释器来优化Python应用程序。

对于有些启动时间相对不重要,并且即时编译器(JIT)可以提高效率的应用,可以考虑使用PyPy。

对于性能优先并且有更多静态变量的代码部分,请考虑使用Cython。

多线程爬取表情包

有一个网站,叫做“斗图啦”,网址是:https://www.doutula.com/。这里面包含了许许多多的有意思的斗图图片,还蛮好玩的。有时候为了斗图要跑到这个上面来找表情,实在有点费劲。于是就产生了一个邪恶的想法,可以写个爬虫,把所有的表情都给爬下来。这个网站对于爬虫来讲算是比较友好了,他不会限制你的headers,不会限制你的访问频率(当然,作为一个有素质的爬虫工程师,爬完赶紧撤,不要把人家服务器搞垮了),不会限制你的IP地址,因此技术难度不算太高。但是有一个问题,因为这里要爬的是图片,而不是文本信息,所以采用传统的爬虫是可以完成我们的需求,但是因为是下载图片所以速度比较慢,可能要爬一两个小时都说不准。因此这里我们准备采用多线程爬虫,一下可以把爬虫的效率提高好几倍。

一、分析网站和爬虫准备工作:

构建所有页面URL列表:

这里我们要爬的页面不是“斗图啦”首页,而是最新表情页面https://www.doutula.com/photo/list/,这个页面包含了所有的表情图片,只是是按照时间来排序的而已。我们把页面滚动到最下面,可以看到这个最新表情使用的是分页,当我们点击第二页的时候,页面的URL变成了https://www.doutula.com/photo/list/?page=2,而我们再回到第一页的时候,page又变成了1,所以这个翻页的URL其实很简单,前面这一串https://www.doutula.com/photo/list/?page=都是固定的,只是后面跟的数字不一样而已。并且我们可以看到,这个最新表情总共是有869页,因此这里我们可以写个非常简单的代码,来构建一个从1到869的页面的URL列表:

  1.  

    # 全局变量,用来保存页面的URL的

  2.  

    PAGE_URL_LIST = []

  3.  

    BASE_PAGE_URL = 'https://www.doutula.com/photo/list/?page='

  4.  

    for x in range(1, 870):

  5.  

    url = BASE_PAGE_URL + str(x)

  6.  

    PAGE_URL_LIST.append(url)

获取一个页面中所有的表情图片链接:

我们已经拿到了所有页面的链接,但是还没有拿到每个页面中表情的链接。经过分析,我们可以知道,其实每个页面中表情的HTML元素构成都是一样的,因此我们只需要针对一个页面进行分析,其他页面按照同样的规则,就可以拿到所有页面的表情链接了。这里我们以第一页为例,跟大家讲解。首先在页面中右键->检查->Elements,然后点击Elements最左边的那个小光标,再把鼠标放在随意一个表情上,这样下面的代码就定位到这个表情所在的代码位置了:

图片 1

01.png

可以看到,这个img标签的class是等于img-responsive lazy image_dtz,然后我们再定位其他表情的img标签,发现所有的表情的img标签,他的class都是img-responsive lazy image_dtz

图片 2

02.png

图片 3

03.png

因此我们只要把数据从网上拉下来,然后再根据这个规则进行提取就可以了。这里我们使用了两个第三方库,一个是requests,这个库是专门用来做网络请求的。第二个库是bs4,这个库是专门用来把请求下来的数据进行分析和过滤用的,如果没有安装好这两个库的,可以使用以下代码进行安装(我使用的是python2.7的版本):

  1.  

    # 安装requests

  2.  

    pip install requests

  3.  

    # 安装bs4

  4.  

    pip install bs4

  5.  

    # 安装lxml解析引擎

  6.  

    pip install lxml

然后我们以第一个页面为例,跟大家讲解如何从页面中获取所有表情的链接:

  1.  

    # 导入requests库

  2.  

    import requests

  3.  

    # 从bs4中导入BeautifulSoup

  4.  

    from bs4 import BeautifulSoup

  5.  

     

  6.  

    # 第一页的链接

  7.  

    url = 'https://www.doutula.com/photo/list/?page=1'

  8.  

    # 请求这个链接

  9.  

    response = requests.get(url)

  10.  

    # 使用返回的数据,构建一个BeautifulSoup对象

  11.  

    soup = BeautifulSoup(response.content,'lxml')

  12.  

    # 获取所有class='img-responsive lazy image_dtz'的img标签

  13.  

    img_list = soup.find_all('img', attrs={'class': 'img-responsive lazy image_dta'})

  14.  

    for img in img_list:

  15.  

    # 因为src属性刚开始获取的是loading的图片,因此使用data-original比较靠谱

  16.  

    print img['data-original']

这样我们就可以在控制台看到本页中所有的表情图片的链接就全部都打印出来了。

下载图片:

有图片链接后,还要对图片进行下载处理,这里我们以一张图片为例:http://ws2.sinaimg.cn/bmiddle/9150e4e5ly1fhpi3ysfocj205i04aa9z.jpg,来看看Python中如何轻轻松松下载一张图片:

  1.  

    import urllib

  2.  

    url = 'http://ws2.sinaimg.cn/bmiddle/9150e4e5ly1fhpi3ysfocj205i04aa9z.jpg'

  3.  

    urllib.urlretrieve(url,filename='test.jpg')

这样就可以下载一张图片了。

结合以上三部分内容:

以上三部分,分别对,如何构建所有页面的URL,一个页面中如何获取所有表情的链接以及下载图片的方法。接下来把这三部分结合在一起,就可以构建一个完整但效率不高的爬虫了:

  1.  

    # 导入requests库

  2.  

    import requests

  3.  

    # 从bs4中导入BeautifulSoup

  4.  

    from bs4 import BeautifulSoup

  5.  

    import urllib

  6.  

    import os

  7.  

     

  8.  

    # 全局变量,用来保存页面的URL的

  9.  

    PAGE_URL_LIST = []

  10.  

    BASE_PAGE_URL = 'https://www.doutula.com/photo/list/?page='

  11.  

    for x in range(1, 870):

  12.  

    url = BASE_PAGE_URL + str(x)

  13.  

    PAGE_URL_LIST.append(url)

  14.  

     

  15.  

     

  16.  

    for page_url in PAGE_URL_LIST:

  17.  

    # 请求这个链接

  18.  

    response = requests.get(page_url)

  19.  

    # 使用返回的数据,构建一个BeautifulSoup对象

  20.  

    soup = BeautifulSoup(response.content,'lxml')

  21.  

    # 获取所有class='img-responsive lazy image_dtz'的img标签

  22.  

    img_list = soup.find_all('img', attrs={'class': 'img-responsive lazy image_dta'})

  23.  

    for img in img_list:

  24.  

    # 因为src属性刚开始获取的是loading的图片,因此使用data-original比较靠谱

  25.  

    src = img['data-original']

  26.  

    # 有些图片是没有http的,那么要加一个http

  27.  

    if not src.startswith('http'):

  28.  

    src = 'http:'+ src

  29.  

    # 获取图片的名称

  30.  

    filename = src.split('/').pop()

  31.  

    # 拼接完整的路径

  32.  

    path = os.path.join('images',filename)

  33.  

    urllib.urlretrieve(src,path)

以上这份代码。可以完整的运行了。但是效率不高,毕竟是在下载图片,要一个个排队下载。如果能够采用多线程,在一张图片下载的时候,就完全可以去请求其他图片,而不用继续等待了。因此效率比较高,以下将该例子改为多线程来实现。

二、多线程下载图片:

这里多线程我们使用的是Python自带的threading模块。并且我们使用了一种叫做生产者和消费者的模式,生产者专门用来从每个页面中获取表情的下载链接存储到一个全局列表中。而消费者专门从这个全局列表中提取表情链接进行下载。并且需要注意的是,在多线程中使用全局变量要用锁来保证数据的一致性。以下是多线程的爬虫代码(如果有看不懂的,可以看视频,讲解很仔细):

  1.  

    #encoding: utf-8

  2.  

     

  3.  

    import urllib

  4.  

    import threading

  5.  

    from bs4 import BeautifulSoup

  6.  

    import requests

  7.  

    import os

  8.  

    import time

  9.  

     

  10.  

    # 表情链接列表

  11.  

    FACE_URL_LIST = []

  12.  

    # 页面链接列表

  13.  

    PAGE_URL_LIST = []

  14.  

    # 构建869个页面的链接

  15.  

    BASE_PAGE_URL = 'https://www.doutula.com/photo/list/?page='

  16.  

    for x in range(1, 870):

  17.  

    url = BASE_PAGE_URL + str(x)

  18.  

    PAGE_URL_LIST.append(url)

  19.  

     

  20.  

    # 初始化锁

  21.  

    gLock = threading.Lock()

  22.  

     

  23.  

    # 生产者,负责从每个页面中提取表情的url

  24.  

    classProducer(threading.Thread):

  25.  

    defrun(self):

  26.  

    while len(PAGE_URL_LIST) > 0:

  27.  

    # 在访问PAGE_URL_LIST的时候,要使用锁机制

  28.  

    gLock.acquire()

  29.  

    page_url = PAGE_URL_LIST.pop()

  30.  

    # 使用完后要及时把锁给释放,方便其他线程使用

  31.  

    gLock.release()

  32.  

    response = requests.get(page_url)

  33.  

    soup = BeautifulSoup(response.content, 'lxml')

  34.  

    img_list = soup.find_all('img', attrs={'class': 'img-responsive lazy image_dta'})

  35.  

    gLock.acquire()

  36.  

    for img in img_list:

  37.  

    src = img['data-original']

  38.  

    if not src.startswith('http'):

  39.  

    src = 'http:'+ src

  40.  

    # 把提取到的表情url,添加到FACE_URL_LIST中

  41.  

    FACE_URL_LIST.append(src)

  42.  

    gLock.release()

  43.  

    time.sleep(0.5)

  44.  

     

  45.  

    # 消费者,负责从FACE_URL_LIST提取表情链接,然后下载

  46.  

    classConsumer(threading.Thread):

  47.  

    defrun(self):

  48.  

    print '%s is running' % threading.current_thread

  49.  

    while True:

  50.  

    # 上锁

  51.  

    gLock.acquire()

  52.  

    if len(FACE_URL_LIST) == 0:

  53.  

    # 不管什么情况,都要释放锁

  54.  

    gLock.release()

  55.  

    continue

  56.  

    else:

  57.  

    # 从FACE_URL_LIST中提取数据

  58.  

    face_url = FACE_URL_LIST.pop()

  59.  

    gLock.release()

  60.  

    filename = face_url.split('/')[-1]

  61.  

    path = os.path.join('images', filename)

  62.  

    urllib.urlretrieve(face_url, filename=path)

  63.  

     

  64.  

    if __name__ == '__main__':

  65.  

    # 2个生产者线程,去从页面中爬取表情链接

  66.  

    for x in range(2):

  67.  

    Producer().start()

  68.  

     

  69.  

    # 5个消费者线程,去从FACE_URL_LIST中提取下载链接,然后下载

  70.  

    for x in range(5):

  71.  

    Consumer().start()

本文由澳门至尊网站发布于黑客安全,转载请注明出处:Python发展介绍,为什么Python为这么慢

关键词: