python 并发 ThreadPoolExecutor
正文:
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的更多相关文章
- Python并发复习1 - 多线程
一.基本概念 程序: 指令集,静态, 进程: 当程序运行时,会创建进程,是操作系统资源分配的基本单位 线程: 进程的基本执行单元,每个进程至少包含一个线程,是任务调度和执行的基本单位 > 进程和 ...
- Python并发编程二(多线程、协程、IO模型)
1.python并发编程之多线程(理论) 1.1线程概念 在传统操作系统中,每个进程有一个地址空间,而且默认就有一个控制线程 线程顾名思义,就是一条流水线工作的过程(流水线的工作需要电源,电源就相当于 ...
- Python并发编程一(多进程)
1.背景知识(进程.多道技术) 顾名思义,进程即正在执行的一个过程.进程是对正在运行程序的一个抽象. 进程的概念起源于操作系统,是操作系统最核心的概念,也是操作系统提供的最古老也是最重要的抽象概念之一 ...
- 《转载》Python并发编程之线程池/进程池--concurrent.futures模块
本文转载自Python并发编程之线程池/进程池--concurrent.futures模块 一.关于concurrent.futures模块 Python标准库为我们提供了threading和mult ...
- Python并发编程系列之多线程
1 引言 上一篇博文详细总结了Python进程的用法,这一篇博文来所以说Python中线程的用法.实际上,程序的运行都是以线程为基本单位的,每一个进程中都至少有一个线程(主线程),线程又可以创建子线程 ...
- python并发模块之concurrent.futures(二)
python并发模块之concurrent.futures(二) 上次我们简单的了解下,模块的一些基本方法和用法,这里我们进一步对concurrent.futures做一个了解和拓展.上次的内容点这. ...
- python并发编程&多线程(二)
前导理论知识见:python并发编程&多线程(一) 一 threading模块介绍 multiprocess模块的完全模仿了threading模块的接口,二者在使用层面,有很大的相似性 官网链 ...
- python并发编程&多进程(一)
本篇理论居多,实际操作见: python并发编程&多进程(二) 一 什么是进程 进程:正在进行的一个过程或者说一个任务.而负责执行任务则是cpu. 举例(单核+多道,实现多个进程的并发执行) ...
- 快速了解Python并发编程的工程实现(上)
关于我 一个有思想的程序猿,终身学习实践者,目前在一个创业团队任team lead,技术栈涉及Android.Python.Java和Go,这个也是我们团队的主要技术栈. Github:https:/ ...
随机推荐
- Django 源码阅读笔记(基础视图)
django源码解读之 View View. ContextMixin.TemplateResponseMixin.TemplateView.RedirectView View class View( ...
- 2019-02-09 python爬取mooc视频项目初级简单版
今天花了一下午时间来做这东西,之前没有自己写过代码,50几行的代码还是查了很多东西啊,果然学起来和自己动起手来完全是两码事. 方案:requests库+正则表达式提取视频下载链接+urlretriev ...
- 从零开始的Spring Boot(1、搭建一个Spring Boot项目Hello World)
搭建一个Spring Boot项目Hello World 写在前面 从零开始的Spring Boot(2.在Spring Boot中整合Servlet.Filter.Listener的方式):http ...
- rust 函数-生命周期
记录一下自己理解的生命周期. 每个变量都有自己的生命周期. 在c++里生命周期好比作用域, 小的作用域的可以使用大作用域的变量. 如果把这里的每个作用域取个名,那么就相当于rust里的生命周期注解. ...
- 移动 Ubuntu16.04 桌面左侧的启动器到屏幕底部_设置方法
通过命令行,对 Launcher 的位置进行一下调整. 按下 Ctrl + Alt + t 键盘组合键,调出终端,在终端中输入以下命令: gsettings set com.canonical.Uni ...
- mysql大表在不停机的情况下增加字段该怎么处理
MySQL中给一张千万甚至更大量级的表添加字段一直是比较头疼的问题,遇到此情况通常该如果处理?本文通过常见的三种场景进行案例说明. 1. 环境准备 数据库版本: 5.7.25-28(Percona 分 ...
- 数据库char varchar nchar nvarchar,编码Unicode,UTF8,GBK等,Sql语句中文前为什么加N(一次线上数据存储乱码排查)
背景 公司有一个数据处理线,上面的数据经过不同环境处理,然后上线到正式库.其中一个环节需要将数据进行处理然后导入到另外一个库(Sql Server).这个处理的程序是老大用python写的,处理完后进 ...
- python实现从文件夹随机拷贝出指定数量文件到目标文件夹
为了方便倒腾数据,功能如题,该脚本和操作目录在同一根目录 实际运行时要手动修改程序中:cpfile_rand('img', 'outfile', 10) # 操作目录,输出目录,输出数量 import ...
- ajax前后端交互原理(6)
6.XMLHttpRequest对象 XMLHttpRequest 是一个 API,它为客户端提供了在客户端和服务器之间传输数据的功能.它提供了一个通过 URL 来获取数据的简单方式,并且不会使整个页 ...
- 《JavaScript高级程序设计》(第二版)
这本书的作者是 Nicholas C.Zakas ,博客地址是 http://www.nczonline.net/ ,大家可以去多关注,雅虎的前端工程师,是YUI的代码贡献者,可想而知这本书得含金量, ...