Python并发concurrent.futures和asyncio实例


Posted in Python onMay 04, 2020

说明

Python标准库为我们提供了threading和multiprocessing模块编写相应的多线程/多进程代码。

从Python3.2开始,标准库为我们提供了concurrent.futures模块,concurrent.futures 模块的主要特色是 ThreadPoolExecutor 和

ProcessPoolExecutor 类,这两个类实现的接口能分别在不同的线程或进程中执行可调

用的对象。这两个类在内部维护着一个工作线程或进程池,以及要执行的任务队列。

Python 3.4 以后标准库中asyncio 包,这个包使用事件循环驱动的协程实现并发。这是 Python 中最大也

是最具雄心壮志的库之一。asyncio 大量使用 yield from 表达式,因此与

Python 旧版不兼容。

submit和map方法

submit方法作用是向线程池提交可回调的task,并返回一个回调实例。

example:

import time
from concurrent.futures import ThreadPoolExecutor

# 可回调的task
def pub_task(msg):
  time.sleep(3)
  return msg

# 创建一个线程池
pool = ThreadPoolExecutor(max_workers=3)

# 往线程池加入2个task
task1 = pool.submit(pub_task, 'a')
task2 = pool.submit(pub_task, 'b')

print(task1.done())    # False
time.sleep(4)
print(task2.done())    # True

print(task1.result())
print(task2.result())

map方法是创建一个迭代器,回调的结果有序放在迭代器中。

问题:

Executor.map 函数易于使用,不过有个特性可能有用,也可能没用,具体情况取决于需求:这个函数返回结果的顺序与调用开始的顺序一致。

如果第一个调用生成结果用时 10秒,而其他调用只用 1 秒,代码会阻塞 10 秒,获取 map 方法返回的生成器产出的第一个结果。

在此之后,获取后续结果时不会阻塞,因为后续的调用已经结束。

如果必须等到获取所有结果后再处理,这种行为没问题;不过,通常更可取的方式是,不管提交的顺序,只要有结果就获取。

为此,要把 Executor.submit 方法和 futures.as_completed 函数结合起来使用。

from concurrent.futures import ThreadPoolExecutor
import requests

URLS = ['http://www.csdn.com', 'http://qq.com', 'http://www.leasonlove.cn']

def task(url, timeout=10):
  return requests.get(url, timeout=timeout)

pool = ThreadPoolExecutor(max_workers=3)
results = pool.map(task, URLS)

for ret in results:
  print('%s, %s' % (ret.url, ret))

future异步编程

Future可以理解为一个在未来完成的操作,这是异步编程的基础。通常情况下,我们执行io操作,访问url时(如下)在等待结果返回之前会产生阻塞,cpu不能做其他事情,而Future的引入帮助我们在等待的这段时间可以完成其他的操作。

from concurrent.futures import ThreadPoolExecutor
from concurrent.futures import as_completed
import requests

URLS = ['http://www.csdn.cn', 'http://qq.com', 'http://www.leasonlove.cn']

def task(url, timeout=1):
  return requests.get(url, timeout=timeout)

with ThreadPoolExecutor(max_workers=3) as executor:
  future_tasks = [executor.submit(task, url) for url in URLS]

  for f in future_tasks:
    if f.running():
      print('%s is running' % str(f))

  for f in as_completed(future_tasks):
    try:
      ret = f.done()
      if ret:
        f_ret = f.result()
        print('%s, done, result: %s, %s' % (str(f), f_ret.url, f_ret.content))
    except Exception as e:
      # 第一个url无响应
      f.cancel()
      print(str(e))

asyncio库协程实现并发

对于gevent 和 asyncio 建议大家放弃Gevent,拥抱asyncio,asyncio是Python3.4以后标准库。

而且由于Gevent直接修改标准库里面大部分的阻塞式系统调用,包括socket、ssl、threading和 select等模块,而变为协作式运行。

但是我们无法保证你在复杂的生产环境中有哪些地方使用这些标准库会由于打了补丁而出现奇怪的问题。

import asyncio
import time
start = time.time()

async def do(x):
  print('Waiting: ', x)
  await asyncio.sleep(x)
  return 'Finish after {}s'.format(x)

task1 = do(1)
task2 = do(2)
task3 = do(4)

tasks = [
  asyncio.ensure_future(task1),
  asyncio.ensure_future(task2),
  asyncio.ensure_future(task3)
]

loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))

for task in tasks:
  print('Task result: ', task.result())

end = time.time()
print('TIME: ', end - start)

协程与线程

如果使用线程做过重要的编程,你就知道写出程序有多么困难,因为调度程序任何时候都能中断线程。

必须记住保留锁,去保护程序中的重要部分,防止多步操作在执行的过程中中断,防止数据处于无效状态。

而协程默认会做好全方位保护,以防止中断。我们必须显式产出才能让程序的余下部分运行。

对协程来说,无需保留锁,在多个线程之间同步操作,协程自身就会同步,因为在任意时刻只有一个协程运行。

想交出控制权时,可以使用 yield 或 yield from 把控制权交还调度程序。

这就是能够安全地取消协程的原因:按照定义,协程只能在暂停的 yield处取消,因此可以处理 CancelledError 异常,执行清理操作。

补充知识:Python-什么时候使用yield?

简介

很多时候在python代码中见到了yield,没有系统学习过,自己也没有用过。

yield语句延迟了语句的执行,然后发送了一个值给调用者,但保留了一定的状态去保证函数离开之后可以继续。当继续的时候,函数继续执行上一个的运行状态。这使得它的代码可以随着时间产生一系列的值,而不是立即执行,然后像一个list一样发送他们回来。

例子

例子1:

# A Simple Python program to demonstrate working 
# of yield 
 
# A generator function that yields 1 for first time, 
# 2 second time and 3 third time 
def simpleGeneratorFun(): 
  yield 1
  yield 2
  yield 3
 
# Driver code to check above generator function 
for value in simpleGeneratorFun(): 
  print(value)

返回语句发送一个特殊的值给它的调用者,而yield产生了一系列的值,当我们想要遍历一个序列的时候,我们应该使用yield,但不想要把整个序列存储在内存中。

yield用于python的生成器(generator)。一个genertator 被定义得看起来像一个普通函数一样,但它需要产生一个数字得时候,它使用yield,而不是使用return。如果一个函数里面定义了yield,那么它自动称为了一个generator函数。、

例子2:

# A Python program to generate squares from 1 
# to 100 using yield and therefore generator 
 
# An infinite generator function that prints 
# next square number. It starts with 1 
def nextSquare(): 
  i = 1; 
 
  # An Infinite loop to generate squares 
  while True: 
    yield i*i         
    i += 1 # Next execution resumes 
        # from this point   
 
# Driver code to test above generator 
# function 
for num in nextSquare(): 
  if num > 100: 
     break  
  print(num)

输出1,4,9…100

以上这篇Python并发concurrent.futures和asyncio实例就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Python 相关文章推荐
怎样使用Python脚本日志功能
Aug 14 Python
python 安装virtualenv和virtualenvwrapper的方法
Jan 13 Python
Python排序搜索基本算法之希尔排序实例分析
Dec 09 Python
python批量查询、汉字去重处理CSV文件
May 31 Python
python生成密码字典的方法
Jul 06 Python
python实现写数字文件名的递增保存文件方法
Oct 25 Python
python实践项目之监控当前联网状态详情
May 23 Python
Python中字符串String的基本内置函数与过滤字符模块函数的基本用法
May 27 Python
Django中create和save方法的不同
Aug 13 Python
如何通过Django使用本地css/js文件
Jan 20 Python
pandas 强制类型转换 df.astype实例
Apr 09 Python
python3.7添加dlib模块的方法
Jul 01 Python
Python 中由 yield 实现异步操作
May 04 #Python
python 双循环遍历list 变量判断代码
May 04 #Python
Python求解排列中的逆序数个数实例
May 03 #Python
Python3实现个位数字和十位数字对调, 其乘积不变
May 03 #Python
python输入一个水仙花数(三位数) 输出百位十位个位实例
May 03 #Python
Python中实现输入一个整数的案例
May 03 #Python
python中使用input()函数获取用户输入值方式
May 03 #Python
You might like
ubuntu10.04配置 nginx+php-fpm模式的详解
2013/06/03 PHP
php抓取页面的几种方法详解
2013/06/17 PHP
iOS自定义提示弹出框实现类似UIAlertView的效果
2016/11/16 PHP
PHP基于rabbitmq操作类的生产者和消费者功能示例
2018/06/16 PHP
jquery高效反选具体实现
2013/05/05 Javascript
一个css与js结合的下拉菜单支持主流浏览器
2014/10/08 Javascript
javascript实现鼠标移到Image上方时显示文字效果的方法
2015/08/07 Javascript
JS实现1000以内被3或5整除的数字之和
2016/02/18 Javascript
详解js数组的完全随机排列算法
2016/12/16 Javascript
JSONP基础知识详解
2017/03/19 Javascript
react开发中如何使用require.ensure加载es6风格的组件
2017/05/09 Javascript
jquery基于layui实现二级联动下拉选择(省份城市选择)
2017/06/20 jQuery
underscore之Chaining_动力节点Java学院整理
2017/07/10 Javascript
React Native 图片查看组件的方法
2018/03/01 Javascript
jQuery实现通过方向键控制div块上下左右移动的方法【测试可用】
2018/04/26 jQuery
微信小程序开发实现消息推送
2020/11/18 Javascript
解决layui checkbox 提交多个值的问题
2019/09/02 Javascript
[01:39:04]DOTA2-DPC中国联赛 正赛 SAG vs CDEC BO3 第二场 2月1日
2021/03/11 DOTA
pyv8学习python和javascript变量进行交互
2013/12/04 Python
使用Python中PDB模块中的命令来调试Python代码的教程
2015/03/30 Python
python虚拟环境virtualenv的安装与使用
2017/09/21 Python
利用Python yagmail三行代码实现发送邮件
2018/05/11 Python
Django-Rest-Framework 权限管理源码浅析(小结)
2018/11/12 Python
Python用字典构建多级菜单功能
2019/07/11 Python
Python如何在main中调用函数内的函数方式
2020/06/01 Python
在pycharm中文件取消用 pytest模式打开的操作
2020/09/01 Python
Matlab使用Plot函数实现数据动态显示方法总结
2021/02/25 Python
canvas生成带二维码海报的踩坑记录
2019/09/11 HTML / CSS
aden + anais英国官网:美国婴儿贴身用品品牌
2019/09/08 全球购物
质检部岗位职责
2013/11/11 职场文书
学生周末长期请假条
2014/02/15 职场文书
2014年单位植树节活动方案
2014/03/23 职场文书
世界红十字日活动总结
2015/02/10 职场文书
心灵捕手观后感
2015/06/02 职场文书
2016年助残日旅游活动总结
2016/04/01 职场文书
用Python爬取英雄联盟的皮肤详细示例
2021/12/06 Python