1,感受
- 自打我用上了concurrent.futures模块,我就深深爱上了它,真是爱不释手(现在我每写一些python模块,都会考虑使用futures加快代码的执行速度。)
- 为啥?因为concurrent.futures好用又简单。
2,如何使用
-
网上也有许多资料解释如何使用该模块,但是确实存在很多坑,毕竟大部分都不是专家级别的,写写博客可能就是日常的笔记而已。。。但是,要是新手看到了,并且按照网友们写的一步一步执行,有时候你就会跌入万丈深渊,我就是受害者之一0.0(em…不排除我写的一些文章也有大坑。。惭愧惭愧0.0)。
-
所以每次接触一个新API的时候,最好先看看官网的解释,这样入坑的可能性会降低很多。所以python3的concurrent.futures模块中文API链接如下:
https://docs.python.org/zh-cn/3/library/concurrent.futures.html
3,我习惯的用法
以下相关代码参考子、自API,分为异步调用和同步调用,那什么时候用异步调用,什么时候用同步调用呢?结合我自身的工程实践,给出我的理解:
- 通常情况下会用异步调用,毕竟速度快,但是我认为条件是,数据规模不是很大,而且并行任务的入队速度和出队速度相差不多的情况下,用异步调用很方便,速度也很快。(解决数据规模大的问题,有很多方法,其中之一是:可以将待处理的大规模数据分块,以分批并行处理)。
- 如果待处理的数据规模超大,也没分块,同时并行任务的入队速度远高于出队速度,那么会出现内存不断增加直至溢出的情况,这样很危险的,会导致服务器崩了。。。。这时候可以考虑同步调用
- 同步调用速度相对慢很多,但是有些情况下可以解决内存溢出的问题。比如并行任务入队操作是从本地文件读取数据,出队操作是对该部分数据进行特别耗时的处理,这样就可能出现内存溢出。
3.1 异步调用
import concurrent.futures
import urllib.request
URLS = ['http://www.foxnews.com/',
'http://www.cnn.com/',
'http://europe.wsj.com/',
'http://www.bbc.co.uk/',
'http://some-made-up-domain.com/']
# Retrieve a single page and report the URL and contents
def load_url(url, timeout):
with urllib.request.urlopen(url, timeout=timeout) as conn:
return conn.read()
# We can use a with statement to ensure threads are cleaned up promptly
with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor:
# Start the load operations and mark each future with its URL
future_to_url = {executor.submit(load_url, url, 60): url for url in URLS}
for future in concurrent.futures.as_completed(future_to_url):
url = future_to_url[future]
try:
data = future.result()
except Exception as exc:
print('%r generated an exception: %s' % (url, exc))
else:
print('%r page is %d bytes' % (url, len(data)))
3.2 同步调用
利用future.result()实现同步调用,示例代码如下:
import concurrent.futures
import urllib.request
URLS = ['http://www.foxnews.com/',
'http://www.cnn.com/',
'http://europe.wsj.com/',
'http://www.bbc.co.uk/',
'http://some-made-up-domain.com/']
# Retrieve a single page and report the URL and contents
def load_url(url, timeout):
with urllib.request.urlopen(url, timeout=timeout) as conn:
return conn.read()
# We can use a with statement to ensure threads are cleaned up promptly
with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor:
# Start the load operations and mark each future with its URL
for url in URLS:
re = executor.submit(load_url, url, 60).result()