祝贺一下自己的头条号通过了新手期~
上篇我们已经讲完了多线程和多进程的基本使用,很简单,两三行代码改写for循环就成,那么,所谓的futures在哪呢?
以及,应该知道线程不是按照既定的列表顺序一个一个跑的,那么,如果中间某个线程出现问题,如何知晓呢?
这个时候就需要另外两个方法了:submit()和as_complete()
首先是submit()函数,它可以排定传入的函数的调用时间,并返回1个future。
而as_complete()通过迭代,可以获取future的结果。future本身有result()方法,用于获取结果,或抛出异常
这两个函数也就是把高度抽象的map()替换了而已,下面来看具体代码:
首先可以看出,2个for循环替换了原本的map()函数。
首先创建了1个dict,通过这个dict把future绑定到其他数据上,因此尽管future在submit()生成时结果顺序不固定,我们仍然可以通过dict做后续处理,比如就像这里用于识别是否存在异常等错误消息。
迭代future时这里的代码略微复杂,本身我们可以直接通过:for future in futures.as_completed(todo):
迭代,只是在这个代码中,添加了1个tqdm模块的函数,用于显示下载进度条:就像平时pip安装模块时看到的那样。
使用方法也很简单,首先我们通过pip安装:pip install tqdm
之后可以看见,这里使用的方法是tqdm.tqdm(),接受了2个参数,第一个是futures.as_completed(todo),也就是1个可迭代的对象(换句话说,可以对其使用for循环的对象),第二个参数是总大小,由于这里的可迭代对象不是列表之类的,本身没有len()函数,所以必须通过这个参数提供预期的总数量,来让tqdm计算剩余的工作量。
然后使用了result()方法以获取结果并抛出异常。在这里,result()返回的值就是传入submit()的函数,也就是get_html()函数返回的值,由于get_html()没有写return,所以返回的是None。
future对象还有1个add_done_callback()方法,用来对result()返回的值回调其他函数进行进一步处理,一般而言我们在submit()提交的函数已经做完了单线程的所有处理(再编写for循环,最后改写for循环为多线程代码),所以这个方法很少用到。之后讲到asyncio时,这个方法出现的场景稍微多一些。
当然,也可以试着把单线程的代码分开,比如只处理获取html,把用lxml解析的函数传入到add_done_callback()中,具体可以自己尝试改写,这里就不再展开了。
最后,通过预先设置的dict,捕捉了抛出异常的future作进一步处理。
以上就是今天的内容,同样的,完整代码可以从https://github.com/lucays/toutiao/tree/master/11获取。