Python 多线程进程高级指南(二)
本文是如何《优雅地实现Python通用多线程/进程并行模块》的后续。因为我发现,自认为懂了一点多线程开发的皮毛,写了那么个multi_helper的玩意儿,后来才发现我靠原来就是一坨屎。自己辛苦开发的并行库,在Python的原生类库中就有了优雅地多的实现。并且还有更优雅的asyncio库!这简直让人累觉不爱。
首先,并行和并发是不同的。100个进程可以在1个CPU上并发地执行,但却能在4个CPU上并行地执行。这就能看出两者的不同。
在实际编程中,有大量的计算或IO是一下子无法结束的。那么如何充分利用各种资源呢?有两个流派:
- 多进程,多线程(并行)
 - 协程 (并发)
 
本文实在不能算完整,但汇集了笔者觉得很精髓的不少内容,因此可以认为是一篇综述性文章。
多线程和多进程
先说前者,定义本身是常识就不多说。初级程序员为了让程序变快,于是就狂开线程,不论是IO操作还是计算,能开100个就绝不开50个。线程回收一律不管,这程序只能是玩具。
不过,众所周知Python有GIL(全局解释器锁),任何时候都只有一个线程在工作。那多线程加速还玩个屁啊?!龟叔站出来了,他说:
- Python在IO操作时,会自动释放GIL,因此IO密集型程序的多线程是有意义的
 - 即使不能多线程,还能多进程,这才是核武器。而Python有非常好用的multiprocessing库解决进程间协同问题。
 
然而,这些耗时任务,如果不需要知道结果,那还好说(很多程序员直接就把结果写到不同的文件里去,从而避免此问题,太low了)。可是每次都写文件再读出来这太麻烦了。如何收集计算结果呢?
笔者那个工具的做法,是将结果保存到一个队列中,从外部对其进行消费。但Python官方库早就有类似的实现了,多线程和多进程版本分别叫ThreadPoolExecutor和ProcessPoolExecutor。至于怎么用,出门问度娘。老司机在文章里贴代码太没有逼格了。
好,你度娘上完了。我们会发现他们都在concurrent.futures库里。这个表述很有意思。这是未来才能知道结果的任务,因此叫future。 在《Python高手之路》的第14章里,这样的概念叫期物。你如果你要获取某个任务的result,就必须等待该任务完成。也可以创建任务的数组,然后批量去执行它。类似的还有C#的async关键字以及task的result属性。
让我觉得比较神奇的是,Python的python-parallelize库,就能隐含地将for循环转换为并行for循环,代码更加简洁。这才是多进程的终极神器。写法如下:
import os
from parallelize import parallelize
for i in parallelize(range(100)):
    print(os.getpid(), i)
你要做的,仅仅是在迭代器外面套上套子,其他并行的操作就都由它执行完了。你猜这个库的核心代码有多少行?30行不到!它用os.fork创建出很多子进程,之后将不同的任务分配到这些进程上。而代码编写和串行程序几乎没有区别。
对多数人来说,高阶函数本来就比较反人类。这样写下来反而会清爽很多。值得学习!这部分写完了,我们进入协程的神秘世界。
asyncio 和 yield from
协程(coroutine)是比线程更轻量级的概念。大家会好奇协程的本质,因为当年学C语言时可是完全没这个东西啊。协程说白了就是语法糖。编译器会把协程的一坨东西整合到大的状态机里,类似于一堆switch-case和while的代码里,从而实现无缝调度。但对代码编写者来说,同一语义的依然能在同一个代码位置,从而更好理解。
yield是Python中的关键字。我们熟悉的是它的迭代生成器用法。更高阶的则是协程。例如:
a=yield b
如果你认为a=b,那就大错特错了。a是外部send函数的返回值。至于更详细的信息,可参考
到了Python3, 更丧心病狂的yield from横空出世。最浅显的理解,是下面的代码:
def merge():
    yield from 'ABC'
    yield from '123'
于是在merge执行循环时,A,B,C,1,2,3会依次返回。那么肯定会有人纳闷,为何不直接itertools.chain呢?因为yield from有更复杂的功能,即能够让外部的generator对内部做消息传递。yield from 就像一个套子,无缝地将生成器merge了起来。
更详细的信息,可参考
它有什么用呢?asyncio.
如果你喜欢C#的await和async关键字,则一定会对它的表现印象深刻。异步函数再也不用像js那样做疯狂的回调,顿时代码清晰了很多。这些也是编译器大人的功劳。
详细的可参考:
看得其实还是晕乎乎的,尽管我自认为对yield和协程有了相对充分的了解却依然如此。
结语
大神说,不要重复造轮子。你会发现之前想做的所有事情,都有远比你想的优雅的多的实现。
不过问题在于,用了协程,yield from, asyncio,别人就看不懂我写的代码了,并且不得不升级到py3,可维护性顿时下降很多。因为我发现,就我身边会python的人来说,熟悉且能灵活使用以上那些语义的人不到百分之一。
有任何问题,随时交流。
Python 多线程进程高级指南(二)的更多相关文章
- Python 多线程、多进程 (二)之  多线程、同步、通信
		
Python 多线程.多进程 (一)之 源码执行流程.GIL Python 多线程.多进程 (二)之 多线程.同步.通信 Python 多线程.多进程 (三)之 线程进程对比.多线程 一.python ...
 - python进阶-------进程线程(二)
		
Python中的进程线程(二) 一.python中的"锁" 1.GIL锁(全局解释锁) 含义: Python中的线程是操作系统的原生线程,Python虚拟机使用一个全局解释器锁(G ...
 - Python多线程&进程
		
一.线程&进程 对于操作系统来说,一个任务就是一个进程(Process),比如打开一个浏览器就是启动一个浏览器进程,打开一个记事本就启动了一个记事本进程,打开两个记事本就启动了两个记事本进程, ...
 - python多线程和多进程(二)
		
---恢复内容开始--- 一.多进程 1.multiprocessing模块用来开启子进程,并在子进程中执行我们定制的任务(比如函数),该模块与多线程模块threading的编程接口类似. impor ...
 - Python 多线程 进程与线程相关概念 (一)
		
0x00 并行和并发 并行:同时做某些事,可以互不干扰的同一时刻做几件事. 并发:也是同时做某些事,但是强调,同一时刻做了几件事. 0x01 并发的解决: 1)队列.缓冲区: 排队就是队列,先进先出. ...
 - Python 多线程、多进程 (三)之 线程进程对比、多进程
		
Python 多线程.多进程 (一)之 源码执行流程.GIL Python 多线程.多进程 (二)之 多线程.同步.通信 Python 多线程.多进程 (三)之 线程进程对比.多线程 一.多线程与多进 ...
 - Python 多线程和线程池
		
一,前言 进程:是程序,资源集合,进程控制块组成,是最小的资源单位 特点:就对Python而言,可以实现真正的并行效果 缺点:进程切换很容易消耗cpu资源,进程之间的通信相对线程来说比较麻烦 线程:是 ...
 - Python 多线程、多进程 (一)之 源码执行流程、GIL
		
Python 多线程.多进程 (一)之 源码执行流程.GIL Python 多线程.多进程 (二)之 多线程.同步.通信 Python 多线程.多进程 (三)之 线程进程对比.多线程 一.python ...
 - Python 多线程、进程、协程上手体验
		
浅谈 Python 多线程.进程.协程上手体验 前言:浅谈 Python 很多人都认为 Python 的多线程是垃圾(GIL 说这锅甩不掉啊~):本章节主要给你体验下 Python 的两个库 Thre ...
 
随机推荐
- java中的static和final关键字
			
一:static 1)修饰成员变量: static关键字可以修饰成员变量,它所修饰的成员变量不属于对象的数据结构,而是属于类的变量,通常通过类名来引用static成员. 当创建对象后,成员变量是存储在 ...
 - MVC过滤器简单理解
			
之前对于MVC过滤器的理解一直处于很模糊的状态,就在网上找了一些很简单的案例做了一下学习,就找了一个比较容易理解的demo分享给大家. 新建一个MVC4项目,可以在global.asax文件中看到如下 ...
 - 高频dom操作和页面性能优化(转载)
			
作者:gxt19940130 原文:https://feclub.cn/post/content/dom 一.DOM操作影响页面性能的核心问题 通过js操作DOM的代价很高,影响页面性能的主要问题有如 ...
 - python中使用selenium调用Firefox缺少geckodriver解决方法
			
from selenium import webdriver driver=webdriver.Firefox() 会报错 解决方法: 因为缺少geckodriver.exe,先到https://gi ...
 - 模板文件引入css样式文件
			
引用路径问题:相对路径和绝对路径 相对路径:相对路口文件index.php设置 绝对路径:从虚拟主机站点目录开始设置 css样式文件引入图片,路径的设置 相对地址:相对css文件本身设置 ①模板文件 ...
 - Python中的选择排序
			
选择排序 选择排序(Selection sort)是一种简单直观的排序算法.它的工作原理如下.首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大 ...
 - 二叉树的递归遍历 Tree UVa548
			
题意:给一棵点带权的二叉树的中序和后序遍历,找一个叶子使得他到根的路径上的权值的和最小,如果多解,那该叶子本身的权值应该最小 解题思路:1.用getline()输入整行字符,然后用stringstre ...
 - webStorm和Sublime使用列编辑命令
			
webStorm可以像Sublime一样使用列编辑,只是区别在于webStorm只可以编辑连续列表. 按住alt键鼠标选择一列,然后输入文字就会编辑多行,这个功能很赞,比较实用(按住ALT键选中之后, ...
 - HDU 4162 	Shape Number(字符串,最小表示法)
			
HDU 4162 题意: 给一个数字串(length <= 300,000),数字由0~7构成,求出一阶差分码,然后输出与该差分码循环同构的最小字典序差分码. 思路: 第一步是将差分码求出:s[ ...
 - EventBus在Android中的简单使用
			
EventBus是一个方便与Android中各组件通信的开源框架,开源地址;https://github.com/greenrobot/EventBus.EventBus功能非常强大 ,今天在做一个功 ...