文章目录

  • 1. futures.ThreadPoolExecutor
  • 2. 期物
  • 3. 阻塞型I/O和GIL
  • 4. 使用concurrent.futures模块启动进程

learning from 《流畅的python》

1. futures.ThreadPoolExecutor

import os
import time
import sys
import requestsPOP20_CC = ('CN IN US ID BR PK NG BD RU JP ' 'MX PH VN ET EG DE IR TR CD FR').split()
BASE_URL = 'http://flupy.org/data/flags'
DEST_DIR = './'def save_flag(img, filename):  # 保存图像path = os.path.join(DEST_DIR, filename)with open(path, 'wb') as fp:fp.write(img)def get_flag(cc):  # 获取图像url = '{}/{cc}/{cc}.gif'.format(BASE_URL, cc=cc.lower())resp = requests.get(url)return resp.contentdef show(text):  # 打印信息print(text, end=' ')sys.stdout.flush()def download_many(cc_list):for cc in sorted(cc_list):image = get_flag(cc)  # 获取show(cc)  # 打印save_flag(image, cc.lower() + '.gif')  # 保存return len(cc_list)def main(download_many):t0 = time.time()count = download_many(POP20_CC)elapsed = time.time() - t0msg = '\n{} flags downloaded in {:.2f}s'print(msg.format(count, elapsed))  # 计时信息# ----使用 futures.ThreadPoolExecutor 类实现多线程下载
from concurrent import futuresMAX_WORKERS = 20  # 最多使用几个线程def download_one(cc):image = get_flag(cc)show(cc)save_flag(image, cc.lower() + '.gif')return ccdef download_many_1(cc_list):workers = min(MAX_WORKERS, len(cc_list))with futures.ThreadPoolExecutor(workers) as executor:#  使用工作的线程数实例化 ThreadPoolExecutor 类;#  executor.__exit__ 方法会调用 executor.shutdown(wait=True) 方法,#  它会在所有线程都执行完毕 前阻塞线程res = executor.map(download_one, sorted(cc_list))# download_one 函数 会在多个线程中并发调用;# map 方法返回一个生成器,因此可以迭代, 获取各个函数返回的值return len(list(res))if __name__ == '__main__':# main(download_many) # 24 秒main(download_many_1)  # 3 秒

2. 期物

  • 通常不应自己创建期物
  • 只能由并发框架(concurrent.futuresasyncio)实例化
    原因:期物 表示终将发生的事情,其 执行的时间 已经排定。因此,只有排定把某件事交给 concurrent.futures.Executor 子类处理时,才会创建 concurrent.futures.Future 实例
    例如,Executor.submit() 方法的参数是一个可调用的对象,调用这个方法后会为传入的可调用对象 排期,并返回一个期物
def download_many_2(cc_list):cc_list = cc_list[:5]with futures.ThreadPoolExecutor(max_workers=3) as executor:to_do = []for cc in sorted(cc_list):future = executor.submit(download_one, cc)# executor.submit 方法排定可调用对象的执行时间,# 然后返回一个 期物,表示这个待执行的操作to_do.append(future) # 存储各个期物msg = 'Scheduled for {}: {}'print(msg.format(cc, future))results = []for future in futures.as_completed(to_do):# as_completed 函数在期物运行结束后产出期物res = future.result() # 获取期物的结果msg = '{} result: {!r}'print(msg.format(future, res))results.append(res)return len(results)
输出:
Scheduled for BR: <Future at 0x22da99d2d30 state=running>
Scheduled for CN: <Future at 0x22da99e1040 state=running>
Scheduled for ID: <Future at 0x22da99e1b20 state=running>
Scheduled for IN: <Future at 0x22da99ec520 state=pending>
Scheduled for US: <Future at 0x22da99ecd00 state=pending>
CN <Future at 0x22da99e1040 state=finished returned str> result: 'CN'
BR <Future at 0x22da99d2d30 state=finished returned str> result: 'BR'
ID <Future at 0x22da99e1b20 state=finished returned str> result: 'ID'
IN <Future at 0x22da99ec520 state=finished returned str> result: 'IN'
US <Future at 0x22da99ecd00 state=finished returned str> result: 'US'5 flags downloaded in 3.20s

3. 阻塞型I/O和GIL

CPython 解释器本身就不是线程安全的,因此有全局解释器锁(GIL), 一次只允许使用一个线程执行 Python 字节码。因此,一个 Python 进程 通常不能同时使用多个 CPU 核心

标准库中所有执行阻塞型 I/O 操作的函数,在等待操作系统返回结果时 都会释放 GIL
这意味着在 Python 语言这个层次上可以使用多线程,而 I/O 密集型 Python 程序能从中受益:一个 Python 线程等待网络响应时,阻塞型 I/O 函数会释放 GIL,再运行一个线程(网络下载,文件读写都属于 IO 密集型)

4. 使用concurrent.futures模块启动进程

这个模块实现的是真正 的并行计算,因为它使用 ProcessPoolExecutor 类把工作分配给多个 Python 进程处理。
因此,如果需要做 CPU 密集型处理,使用这个模块 能绕开 GIL,利用所有可用的 CPU 核心

点击查看:进程、线程概念差异

使用 concurrent.futures 模块能特别轻松地 把 基于线程 的方案转成 基于进程 的方案

ProcessPoolExecutor 的价值体现在 CPU 密集型 作业上

python 使用期物处理并发相关推荐

  1. python实现摄像头拍照_使用Python控制摄像头拍照并发邮件

    o1 前言 为什么会有写这个程序的想法呢? 最初的想法是写一个可以用电脑前置摄像头拍照的程序,在舍友使用你电脑的时候,不经意间获取到一大堆奇葩舍友的表情包. 然后我又突发奇想,要不搞个开机启动吧,这样 ...

  2. python之socketserver实现并发

    python之socketserver实现并发 服务端 import socketserver #socketserver模块是用来实现并发 # 我们自己的类里一定要继承socketserver.Ba ...

  3. python并发循环_在Python中模拟一个并发循环?

    在Python中模拟一个并发循环? 我需要模拟Python程序中的并发循环.不幸的是,以下简单的代码不起作用:list_of_ints = [ 1, 2, 3 ]iterator = list_of_ ...

  4. python go高并发_天下武功为快不破,戏说Python与Go高并发争锋!

    在这个以斗气大陆横行的世界,每一个大的势力宗门都有自己的杀手锏的功法,比如老牌的古族有C++这样的巨无霸语言,药族有C语言,几乎斗气大陆所有的操作系统都是用C语言做的,毕竟斗气都要靠吃丹药维持.而实力 ...

  5. 天下武功为快不破,戏说Python与Go高并发争锋!

    在这个以斗气大陆横行的世界,每一个大的势力宗门都有自己的杀手锏的功法,比如老牌的古族有C++这样的巨无霸语言,药族有C语言,几乎斗气大陆所有的操作系统都是用C语言做的,毕竟斗气都要靠吃丹药维持.而实力 ...

  6. Python通过future处理并发

    future初识 通过下面脚本来对future进行一个初步了解: 例子1:普通通过循环的方式 1 import os 2 import time 3 import sys 4 5 import req ...

  7. Python Tornado搭建高并发Restful API接口服务

    Tornado 和现在的主流 Web 服务器框架(包括大多数 Python 的框架)有着明显的区别:它是非阻塞式服务器,而且速度相当快能实现高并发.得利于其 非阻塞的方式和对epoll的运用,Torn ...

  8. python如何解决高并发_Flask 处理高并发、多线程

    前言: 使用flask做服务时,可以使用python run.py的方式运行,但是这样不能用于生产环境,可能会出现连接无响应的情况.后来通过查找资料,发现flask服务处理多线程.高并发的一下方法,主 ...

  9. python和java对比并发_Python并发编程之从性能角度来初探并发编程(一)

    本文目录并发编程的基本概念 单线程VS多线程VS多进程 性能对比成果总结 前言 作为进阶系列的一个分支「并发编程」,我觉得这是每个程序员都应该会的. 并发编程 这个系列,我准备了将近一个星期,从知识点 ...

最新文章

  1. 分布式CAP中情侣的纠缠故事,真是剪不断 理还乱!
  2. js调用QQ进程的方法总结
  3. [Ubuntu] 如何在Ubuntu11.04将PHP5.3降级到PHP5.2
  4. 【《Objective-C基础教程 》笔记】(八)OC的基本事实和OC杂七杂八的疑问
  5. 简谈Redis的线程模型
  6. 20以内混合加减法100题_一年级数学20以内加减法混合运算练习题,寒假练习巩固!...
  7. python pip3 pip_Python:pip 和pip3的区别
  8. python中怎样向字典中添加值_python的字典中,如何向指定路径添加值?
  9. php和mssql连接好吗,php如何与mssql数据库连接与配置_PHP教程
  10. 企业上云势不可挡 安全策略该如何制定?
  11. hdu 4288 线段树 暴力 **
  12. 软件测试时间特性,软件测试-第九章调试特性
  13. Luogu3810 三维偏序(陌上花开)
  14. python3安装M2Crypto模块
  15. 智能门锁的千亿市场,为何迟迟不来?
  16. 8086汇编实现 加密解密软件
  17. 外贸建站需要注意的地方
  18. Python 计算变上限二重积分的数值模拟基础
  19. 使用Bitbucket Cloud学习Git
  20. Android 8内测版本,安卓qq v8.0.8内测版

热门文章

  1. Linux下C语言程序的内存布局
  2. 保护可执行程序的一种方法
  3. 1、绪论初识机器学习
  4. 织梦文章添加字段填栏目id,内容页调用字段里的栏目文章
  5. ASP.NET获取路径的方法
  6. 十大经典算法 - 转载
  7. 【Ubuntu】ubuntu系统下python3和python2环境自由切换
  8. [转]微信小程序登录逻辑梳理
  9. canvas小程序-快跑程序员
  10. 在Delphi中使用indy SMTP发送gmail邮件[转]