从Python源代码里面证明你的猜想

数据测
• 阅读 129

看过《Python爬虫开发 从入门到实战》的同学,应该对multiprocessing这个模块比较熟悉,在书上我使用这个模块通过几行代码实现了一个简单的多线程爬虫:

(想自学习编程的小伙伴请搜索圈T社区,更多行业相关资讯更有行业相关免费视频教程。完全免费哦!)

import requests
from multiprocessing.dummy import Pool

def get(url):
    print(requests.get(url).text, '\n')

url_list = [
    'http://exercise.kingname.info/exercise_middleware_ip/1',
    'http://exercise.kingname.info/exercise_middleware_ip/2',
    'http://exercise.kingname.info/exercise_middleware_ip/3',
    'http://exercise.kingname.info/exercise_middleware_ip/4'
]

pool = Pool(3)
result = pool.map(get, url_list)

运行效果如下图所示:
从Python源代码里面证明你的猜想

(没有看过我的书的人可能会质疑,multiprocessing不是多进程模块吗?为什么你说是多线程?看过书的读者不会有这个疑惑,因为我在书上解释过原因)

现在,你有一个函数,没有任何参数,但是仍然想让他使用多线程,于是模仿上面的代码,你这样写:

import requests
from multiprocessing.dummy import Pool

def test():
    print('函数运行成功!')


pool = Pool(3)
result = pool.map(test, ())

运行以后发现,什么都没有打印出来,也就是说test()函数根本没有运行。

如果你强行给函数添加一个没用的参数,结果又正常了:

import requests
from multiprocessing.dummy import Pool

def test(_):
    print('函数运行成功!\n')


pool = Pool(3)
result = pool.map(test, (0, ) * 3)

运行效果如下图所示。
从Python源代码里面证明你的猜想
所以你隐隐觉得,如果pool.map的第二个参数是空的可迭代对象,那么函数就不会运行。

(当然,使用过Python自带的map函数的同学肯定直接就知道这一点,不过本文依然使用它来做例子,用于说明阅读源代码的方法。)

为了证明这一点,我们打开Python安装目录/lib/multiprocessing/pool.py文件,在里面找到def map(self, func, iterable, chunksize=None)这一行,如下图所示:
从Python源代码里面证明你的猜想
(本文使用Python 3.7.3作为演示,如果你的Python版本不是3.7.3,那么代码可能会有一些区别)

从代码里面可以看到,这里调用了self._map_async(),传入参数,获得返回值以后,再调用了返回值的.get()方法。

所以继续看self._map_async()方法:
从Python源代码里面证明你的猜想
在这个方法里面,如果我们传入的可迭代对象为空,那么也就是这里的参数iterable为空。于是

chunksize = 0
len(iterable) = 0

map的第一个参数,函数名被传入了下面这一行代码中:

task_batches = Pool._get_tasks(func, iterable, chunksize)

查看Pool._get_tasks这个静态方法,可以看到:
从Python源代码里面证明你的猜想
由于这里的参数it就是空的可迭代对象,size为0,所以下面这一行代码返回空元组:

tuple(itertools.islice(it, size))

这个生成器直接就会结束,最后一行yield (func, x)根本不会执行。

再来看代码里使用MapResult类初始化了一个result对象,然后返回这个对象。

再进入到MapResult类里面,如下图所示:
从Python源代码里面证明你的猜想
在这段__init__中,可以得到如下几个参数的值:

self._success = True
self._value = []  # 因为[None] * 0 结果为[]
self._event.set()

返回的result对象的.get()方法被调用了。但是由于MapResult本身没有.get()方法,于是变为调用父类ApplyResult.get()方法。

再进入ApplyResult里面,查看.get()方法:
从Python源代码里面证明你的猜想
由于前面调用了self._event.set(),所以这里的self.ready()结果为True,而由于self._success在上面为True,所以这里直接return self._value。也就是返回一个空的列表。

到此为止,在pool.map的第二个参数为空的可迭代对象时,所有的流程就走完了。整个过程中,没有涉及到任何调用func的过程。所以原有的函数不会被执行。

最后说说为什么在本文中我们看的是multiprocessingPool类里面的map方法,而不是multiprocessing.dummyPool类里面的map方法。

这是因为,如果我们打开Python安装路径/Lib/multiprocessing/dummy/__init__.py,我们就可以看到,它的Pool实际上返回的是一个ThreadPool对象。而这个对象的代码,实际上也在Python安装路径/Lib/multiprocessing/pool.py文件中,并且继承自Pool类。所以他们的map方法的代码是完全一样的。

点赞
收藏
评论区
推荐文章
Irene181 Irene181
4年前
盘点最重要的7个Python库
点击上方“Python爬虫与数据挖掘”,进行关注回复“书籍”即可获赠Python从入门到进阶共10本电子书导读:对于那些对Python数据生态系统不太熟悉的人士,我将简要地介绍一部分重要的库。作者:韦斯·麦金尼(WesMcKinney)译者:徐敬来源:大数据DT(ID:hzdashuju)01NumPyhttp://numpy
Wesley13 Wesley13
4年前
50 行代码教你爬取猫眼电影 TOP100 榜所有信息
对于Python初学者来说,爬虫技能是应该是最好入门,也是最能够有让自己有成就感的,今天,恋习Python的手把手系列,手把手教你入门Python爬虫,爬取猫眼电影TOP100榜信息,将涉及到基础爬虫架构中的HTML下载器、HTML解析器、数据存储器三大模块:HTML下载器:利用requests模块下载HTML网页;HTML解析器:利用re正则表达
Stella981 Stella981
4年前
25条很棒的Python一行代码,建议收藏!
点击上方“Python爬虫与数据挖掘”,进行关注回复“书籍”即可获赠Python从入门到进阶共10本电子书今日鸡汤中岁颇好道,晚家南山陲。自从我用Python编写第一行代码以来,就被它的简单性、出色的可读性和特别流行的一行代码所吸引。在下面,我将给大家介绍并解释一些Python一行程序。
Stella981 Stella981
4年前
Python自带爬虫库urllib使用大全
击上方“Python爬虫与数据挖掘”,进行关注回复“书籍”即可获赠Python从入门到进阶共10本电子书今日鸡汤门前冷落鞍马稀,老大嫁作商人妇。这篇文章主要来讲解下Python自带的爬虫库urllib常见用法,主要围绕urllib定义、urllib的常用模块和urlliblxml爬虫案例三个部分进行展开。
Stella981 Stella981
4年前
Python爬取暴走漫画动态图
最近再之乎上看到比较好的Python爬虫教程,看过之后对爬虫有了大概的了解,随后自己写了个爬取暴走漫画(https://www.oschina.net/action/GoToLink?urlhttp%3A%2F%2Fbaozoumanhua.com%2Fcatalogs%2Fgif)动图的爬虫练练手,另外附上Python爬虫教程(https://w
Stella981 Stella981
4年前
Python(phone)模块获取手机号归属地、区号、运营商等
Python(phone)模块获取手机号归属地、区号、运营商等一、我使用的是python3,可以自行搜索下载二、安装phone模块, pipinstallphone 三、测试代码如下:fromphoneimportPhoneif__name__"__main__":phoneN
Stella981 Stella981
4年前
Python web开发从入门到放弃
点击上方“Python爬虫与数据挖掘”,进行关注回复“书籍”即可获赠Python从入门到进阶共10本电子书今日鸡汤无为之用方为大用。!(https://oscimg.oschina.net/oscnet/f64430c27950bcccce040bb032ea65e73a5.jpg)越来越多的同学知道我在做
Stella981 Stella981
4年前
Python实现王者荣耀小助手(一)
简单来说网络爬虫,是指抓取万维网信息的程序或者脚本,Python在网络爬虫有很大优势,今天我们用Python实现获取王者荣耀相关数据,做一个小助手:前期准备,环境搭建:Python2.7sys模块提供了许多函数和变量来处理Python运行时环境的不同部分;urllib模块提供了一系列用于操作URL的功能,爬虫所需要的功能,基本上在urll
Stella981 Stella981
4年前
Python中的基础数据类型(String,Number)及其常用用法简析
点击上方“Python爬虫与数据挖掘”,进行关注回复“书籍”即可获赠Python从入门到进阶共10本电子书今日鸡汤寄意寒星荃不察,我以我血荐轩辕。Python中的基础数据类型前言哈喽,各位小伙伴们,相信大家和我一样,在开始接触Python这门语言的时候,会遇到很多困
Python进阶者 Python进阶者
1年前
Python网络爬虫的时候json=就是让你少写个json.dumps()
大家好,我是皮皮。一、前言前几天在Python白银交流群【空翼】问了一个Python网络爬虫的问题,提问截图如下:登录请求地址是这个:二、实现过程这里【甯同学】给了一个提示,如下所示:估计很多小伙伴和我一样会有一个疑问吧,为啥这次要用jsondata啊?因