正文:
Executor是一个抽象类,子类:

ThreadPoolExecutor和ProcessPoolExecutor ,一个线程池,一个进程池.

future对象:在未来的某一时刻完成操作的对象.
submit方法可以返回一个future对象,此对象直接返回,等线程函数执行完后把return的数据再set_result到future对象中;

下面实现了submit, map 与 as_completed的差别 , 下面的例子中都没有使用with ,实际使用时需要调用shutdown , 或用with

#线程执行的函数
def add(n1,n2):
v = n1 + n2
print('add :', v , ', tid:',threading.currentThread().ident)
time.sleep(n1)
return v
#通过submit把需要执行的函数扔进线程池中.
#submit 直接返回一个future对象
ex = ThreadPoolExecutor(max_workers=3) #制定最多运行N个线程
f1 = ex.submit(add,2,3)
f2 = ex.submit(add,2,2)
print('main thread running')
print(f1.done()) #done 看看任务结束了没
print(f1.result()) #获取结果 ,阻塞方法

注意 map 方法,返回是跟你提交序列是一致的. 是有序的

#下面是map 方法的简单使用.  注意:map 返回是一个生成器 ,并且是*有序的*
URLS = ['http://www.baidu.com', 'http://www.qq.com', 'http://www.sina.com.cn']
def get_html(url):
print('thread id:',threading.currentThread().ident,' 访问了:',url)
return requests.get(url) #这里使用了requests 模块
ex = ThreadPoolExecutor(max_workers=3)
res_iter = ex.map(get_html,URLS) #内部迭代中, 每个url 开启一个线程
for res in res_iter: #此时将阻塞 , 直到线程完成或异常
print('url:%s ,len: %d'%(res.url,len(res.text)))

接下来,使用as_completed . 这个函数为submit 而生, 为啥呢?

你总想通过一种办法来解决submit后啥时候完成的吧 , 而不是一次次调用future.done 或者 使用 future.result 吧.

concurrent.futures.as_completed(fs, timeout=None) 返回一个生成器,在迭代过程中会阻塞,

直到线程完成或者异常时,返回一个被set_result的Future对象.

同时注意, map方法返回是有序的, as_completed 是那个线程先完成/失败 就返回

#这是一个简单的 as_completed
URLS = ['http://www.baidu.com', 'http://www.qq.com', 'http://www.sina.com.cn']
def get_html(url):
time.sleep(3)
print('thread id:',threading.currentThread().ident,' 访问了:',url)
return requests.get(url) #这里使用了requests 模块
ex = ThreadPoolExecutor(max_workers=3)
f = ex.submit(get_html,URLS[0]) #提交一个任务,放入线程池中,准备执行
print('main thread running')
for future in as_completed([f]): #as_completed()接受一个可迭代的Future序列,返回一个生成器,在完成或异常时返回这个Future对象
print('一个任务完成.')
print(future.result())
#as_completed 完整的例子
#as_completed 返回一个生成器,用于迭代, 一旦一个线程完成(或失败) 就返回
URLS = ['http://www.baidu.com', 'http://www.qq.com', 'http://www.sina.com.cn']
def get_html(url):
time.sleep(1)
print('thread id:',threading.currentThread().ident,' 访问了:',url)
return requests.get(url) #这里使用了requests 模块
ex = ThreadPoolExecutor(max_workers=3) #最多3个线程
future_tasks = [ex.submit(get_html,url) for url in URLS] #创建3个future对象
for future in as_completed(future_tasks): #迭代生成器
try:
resp = future.result()
except Exception as e:
print('%s'%e)
else:
print('%s has %d bytes!'%(resp.url, len(resp.text)))
"""
thread id: 5160 访问了: http://www.baidu.com
thread id: 7752 访问了: http://www.sina.com.cn
thread id: 5928 访问了: http://www.qq.com
http://www.qq.com/ has 240668 bytes!
http://www.baidu.com/ has 2381 bytes!
https://www.sina.com.cn/ has 577244 bytes!
"""

wait 是阻塞函数,第一个参数和as_completed一样, 一个可迭代的future序列,返回一个元组 ,包含2个set , 一个完成的,一个未完成的

"""
wait 例子
参数:
FIRST_COMPLETED 当任何未来完成或被取消时,该函数将返回。 FIRST_EXCEPTION 当任何未来通过提出异常完成时,函数将返回。如果没有未来引发异常,那么它等同于 ALL_COMPLETED。 ALL_COMPLETED(默认) 当所有future完成或被取消时,函数将返回。
"""
URLS = ['http://www.baidu.com', 'http://www.qq.com', 'http://www.sina.com.cn']
def get_html(url):
time.sleep(1)
print('thread id:',threading.currentThread().ident,' 访问了:',url)
return requests.get(url) #这里使用了requests 模块
ex = ThreadPoolExecutor(max_workers=3) #最多3个线程
future_tasks = [ex.submit(get_html,url) for url in URLS] #创建3个future对象
try:
result = wait(future_tasks,return_when = fu.FIRST_COMPLETED)
done_set = result[0]
for future in done_set:
resp = future.result()
print('第一个网页任务完成 url:%s , len:%d bytes! ' % (resp.url, len(resp.text)))
except Exception as e:
print('exception :' , e)
 

最后说一下回调:add_done_callback(fn) , 回调函数是在调用线程完成后再调用的,在同一个线程中.

import os,sys,time,requests,threading
from concurrent import futures URLS = [
'http://baidu.com',
'http://www.qq.com',
'http://www.sina.com.cn'
] def load_url(url):
print('tid:',threading.currentThread().ident,',url:',url)
with requests.get(url) as resp:
return resp.content
def call_back(obj):
print('->>>>>>>>>call_back , tid:',threading.currentThread().ident, ',obj:',obj) with futures.ThreadPoolExecutor(max_workers=3) as ex:
# mp = {ex.submit(load_url,url) : url for url in URLS}
mp = dict()
for url in URLS:
f = ex.submit(load_url,url)
mp[f] = url
f.add_done_callback(call_back)
for f in futures.as_completed(mp):
url = mp[f]
try:
data = f.result()
except Exception as exc:
print(exc, ',url:',url)
else:
print('url:', url, ',len:',len(data),',data[:20]:',data[:20])
"""
tid: 7128 ,url: http://baidu.com
tid: 7892 ,url: http://www.qq.com
tid: 3712 ,url: http://www.sina.com.cn
->>>>>>>>>call_back , tid: 7892 ,obj: <Future at 0x2dd64b0 state=finished returned bytes>
url: http://www.qq.com ,len: 251215 ,data[:20]: b'<!DOCTYPE html>\n<htm'
->>>>>>>>>call_back , tid: 3712 ,obj: <Future at 0x2de07b0 state=finished returned bytes>
url: http://www.sina.com.cn ,len: 577333 ,data[:20]: b'<!DOCTYPE html>\n<!--'
->>>>>>>>>call_back , tid: 7128 ,obj: <Future at 0x2d533d0 state=finished returned bytes>
url: http://baidu.com ,len: 81 ,data[:20]: b'<html>\n<meta http-eq'
"""

python 并发 ThreadPoolExecutor的更多相关文章

  1. Python并发复习1 - 多线程

    一.基本概念 程序: 指令集,静态, 进程: 当程序运行时,会创建进程,是操作系统资源分配的基本单位 线程: 进程的基本执行单元,每个进程至少包含一个线程,是任务调度和执行的基本单位 > 进程和 ...

  2. Python并发编程二(多线程、协程、IO模型)

    1.python并发编程之多线程(理论) 1.1线程概念 在传统操作系统中,每个进程有一个地址空间,而且默认就有一个控制线程 线程顾名思义,就是一条流水线工作的过程(流水线的工作需要电源,电源就相当于 ...

  3. Python并发编程一(多进程)

    1.背景知识(进程.多道技术) 顾名思义,进程即正在执行的一个过程.进程是对正在运行程序的一个抽象. 进程的概念起源于操作系统,是操作系统最核心的概念,也是操作系统提供的最古老也是最重要的抽象概念之一 ...

  4. 《转载》Python并发编程之线程池/进程池--concurrent.futures模块

    本文转载自Python并发编程之线程池/进程池--concurrent.futures模块 一.关于concurrent.futures模块 Python标准库为我们提供了threading和mult ...

  5. Python并发编程系列之多线程

    1 引言 上一篇博文详细总结了Python进程的用法,这一篇博文来所以说Python中线程的用法.实际上,程序的运行都是以线程为基本单位的,每一个进程中都至少有一个线程(主线程),线程又可以创建子线程 ...

  6. python并发模块之concurrent.futures(二)

    python并发模块之concurrent.futures(二) 上次我们简单的了解下,模块的一些基本方法和用法,这里我们进一步对concurrent.futures做一个了解和拓展.上次的内容点这. ...

  7. python并发编程&多线程(二)

    前导理论知识见:python并发编程&多线程(一) 一 threading模块介绍 multiprocess模块的完全模仿了threading模块的接口,二者在使用层面,有很大的相似性 官网链 ...

  8. python并发编程&多进程(一)

    本篇理论居多,实际操作见:  python并发编程&多进程(二) 一 什么是进程 进程:正在进行的一个过程或者说一个任务.而负责执行任务则是cpu. 举例(单核+多道,实现多个进程的并发执行) ...

  9. 快速了解Python并发编程的工程实现(上)

    关于我 一个有思想的程序猿,终身学习实践者,目前在一个创业团队任team lead,技术栈涉及Android.Python.Java和Go,这个也是我们团队的主要技术栈. Github:https:/ ...

随机推荐

  1. git clone 时注意点

    环境: 在公司访问外网需要设置代理,另外,在公司局域网内架设了一台 GIT 服务器. 在使用 git clone 时,不能设置成 git 使用代理: git config --global http. ...

  2. mitmdump+python的使用(代码篇)

    mitmproxy+python代码篇 一.上个推文我们介绍了mitmdump的简单操作,下面我们开始学习,mitmdump配合python脚本的使用.第一点先讲日志输出.请看图片 先导入ctx模块: ...

  3. (二)用testng的groups管理用例

    原文链接:https://www.cnblogs.com/Jourly/p/7002096.html 一.需求: 测试时经常有两种场景,第一种是冒烟测试的小部分用例:一类是全部用例. 二.针对第一种运 ...

  4. 使用torch实现RNN

    (本文对https://blog.csdn.net/out_of_memory_error/article/details/81456501的结果进行了复现.) 在实验室的项目遇到了困难,弄不明白LS ...

  5. java中Proxy类初探

    在java中提供了一个动态代理类,这个类位于java.lang.reflect包中的Proxy类中.什么是动态代理类呢?就是可以在运行时创建一个实现了一组给定接口的新类.听上去有点高深的样子,其实是提 ...

  6. vue+ajax的实现

    html <tr> <td>用户名</td> <td id="t01"><input type="text" ...

  7. Linux环境下操作Oracle数据库命令

    A增量备份 在Oracle用户下进行: 1.su – oracle, pwd to make sure. 2.脚本位置more /home/oracle/arch.sh 3.运行脚本 ./arch.s ...

  8. ROC曲线 vs Precision-Recall曲线

    深入理解对比两个曲线各自的特性和相互的差异需要花不少时间研读一些国外的技术博客与相关paper,暂时先列出下面这么多,这部分后续可以继续补充. ROC曲线和AUC的定义可以参看“ROC曲线于AUC”, ...

  9. 阿里巴巴开源canal 工具数据同步异常CanalParseException:parse row data failed,column size is not match for table......

    一.异常现象截图  二.解决方式: 1.背景 早期的canal版本(<=1.0.24),在处理表结构的DDL变更时采用了一种简单的策略,在内存里维护了一个当前数据库内表结构的镜像(通过desc ...

  10. git配置用户和邮箱

    1. 查看git用户配置 git config user.name 2. 查看git邮箱配置 git config user.email 3. 配置git用户 git config --global ...