in main: get page 4s success
``as_completed()``方法是一个生成器,在没有任务完成的时候,会阻塞,在有某个任务完成的时候,会``yield``这个任务,就能执行for循环下面的语句,然后继续阻塞住,循环到所有的任务结束。从结果也可以看出,**先完成的任务会先通知主线程**。
### **map**
除了上面的``as_completed``方法,还可以使用``executor.map``方法,但是有一点不同。
from concurrent.futures import ThreadPoolExecutor
import time
参数times用来模拟网络请求的时间def get_html(times):
time.sleep(times)
print("get page {}s finished".format(times))
return times
executor = ThreadPoolExecutor(max_workers=2)
urls = [3, 2, 4] # 并不是真的url
for data in executor.map(get_html, urls):
print("in main: get page {}s success".format(data))
执行结果
get page 2s finished
get page 3s finished
in main: get page 3s success
in main: get page 2s success
get page 4s finished
in main: get page 4s success
使用``map``方法,无需提前使用``submit``方法,``map``方法与``python``标准库中的``map``含义相同,都是将序列中的每个元素都执行同一个函数。上面的代码就是对``urls``的每个元素都执行`get_html`函数,并分配各线程池。可以看到执行结果与上面的``as_completed``方法的结果不同,**输出顺序和****`**`**urls**`**`列表的顺序相同**,就算2s的任务先执行完成,也会先打印出3s的任务先完成,再打印2s的任务完成。
### **wait**
``wait``方法可以让主线程阻塞,直到满足设定的要求。
from concurrent.futures import ThreadPoolExecutor, wait, ALL_COMPLETED, FIRST_COMPLETEDimport time
参数times用来模拟网络请求的时间
def get_html(times):
time.sleep(times)
print("get page {}s finished".format(times))
return times
executor = ThreadPoolExecutor(max_workers=2)
urls = [3, 2, 4] # 并不是真的url
all_task = [executor.submit(get_html, (url)) for url in urls]
wait(all_task, return_when=ALL_COMPLETED)print(“main”)
执行结果
get page 2s finished
get page 3s finished
get page 4s finished
main
``wait``方法接收3个参数,等待的任务序列、超时时间以及等待条件。等待条件``return_when``默认为``ALL_COMPLETED``,表明要等待所有的任务都结束。可以看到运行结果中,确实是所有任务都完成了,主线程才打印出``main``。等待条件还可以设置为``FIRST_COMPLETED``,表示第一个任务完成就停止等待。
## 03、源码分析
`cocurrent.future`模块中的``future``的意思是*未来对象*,可以把它理解为**一个在未来完成的操作**,这是异步编程的基础 。在线程池``submit()``之后,返回的就是这个``future``对象,返回的时候任务并没有完成,但会在将来完成。也可以称之为task的返回容器,这个里面会存储task的结果和状态。那``ThreadPoolExecutor``内部是如何操作这个对象的呢?
下面简单介绍``ThreadPoolExecutor``的部分代码:
**1.init方法**
![图片](https://img-blog.csdnimg.cn/img_convert/3c8980cd28569d68093fc95bdb5e627d.jpeg)
``init``方法中主要重要的就是任务队列和线程集合,在其他方法中需要使用到。
**2.submit方法**
![图片](https://img-blog.csdnimg.cn/img_convert/4f7bb4e79da284a4e7d28acbd499cd25.jpeg)
``submit``中有两个重要的对象,``_base.Future()`和`_WorkItem()``对象,``_WorkItem()``对象负责运行任务和对`future`象进行设置,最后会将``future``对象返回,可以看到整个过程是立即返回的,没有阻塞。
**3.adjust\_thread\_count方法**
![图片](https://img-blog.csdnimg.cn/img_convert/f212910d00fe122327da5f239ac72bfa.jpeg)
这个方法的含义很好理解,主要是创建指定的线程数。但是实现上有点难以理解,比如线程执行函数中的weakref.ref,涉及到了弱引用等概念,留待以后理解。
**4.\_WorkItem对象**
![图片](https://img-blog.csdnimg.cn/img_convert/caabf77d493a1fb4f78a931fb7a41e45.jpeg)
``_WorkItem``对象的职责就是执行任务和设置结果。这里面主要复杂的还是``self.future.set_result(result)``。
**5.线程执行函数--\_worker**
![图片](https://img-blog.csdnimg.cn/img_convert/0285e73f293d9617f874d1fa5ef8776a.jpeg)
这是线程池创建线程时指定的函数入口,主要是从队列中依次取出task执行,但是函数的第一个参数还不是很明白。留待以后。
## 04、总结
* future的设计理念很棒,在线程池/进程池和携程中都存在future对象,是异步编程的核心。
* ThreadPoolExecutor 让线程的使用更加方便,减小了线程创建/销毁的资源损耗,无需考虑线程间的复杂同步,方便主线程与子线程的交互。
* 线程池的抽象程度很高,多线程和多进程的编码接口一致。
## **未完成**
* 对future模块的理解。
* weakref.ref是什么?
* 线程执行函数入口\_worker的第一个参数的意思。
**最后感谢每一个认真阅读我文章的人,看着粉丝一路的上涨和关注,礼尚往来总是要有的,虽然不是什么很值钱的东西,如果你用得到的话可以直接拿走!**
![](https://img-blog.csdnimg.cn/a096983111f247d99fb98a93ac5e6e65.png)
### 软件测试面试文档
我们学习必然是为了找到高薪的工作,下面这些面试题是来自阿里、腾讯、字节等一线互联网大厂最新的面试资料,并且有字节大佬给出了权威的解答,刷完这一套面试资料相信大家都能找到满意的工作。
![在这里插入图片描述](https://img-blog.csdnimg.cn/057f075a555e43b5ae94ac4c2c7f6dc1.png#pic_center)
![](https://img-blog.csdnimg.cn/b5d166f9b12b4ce9ba4ef9adcc88eaa1.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210511152217670.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3poaWd1aWd1,size_16,color_FFFFFF,t_70)
**感谢每一个认真阅读我文章的人,看着粉丝一路的上涨和关注,礼尚往来总是要有的:**
① 2000多本Python电子书(主流和经典的书籍应该都有了)
② Python标准库资料(最全中文版)
③ 项目源码(四五十个有趣且经典的练手项目及源码)
④ Python基础入门、爬虫、web开发、大数据分析方面的视频(适合小白学习)
⑤ Python学习路线图(告别不入流的学习)
**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**
**[需要这份系统化学习资料的朋友,可以戳这里无偿获取](https://bbs.csdn.net/topics/618317507)**
**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**