本文是如何《优雅地实现Python通用多线程/进程并行模块》的后续。因为我发现,自认为懂了一点多线程开发的皮毛,写了那么个multi_helper的玩意儿,后来才发现我靠原来就是一坨屎。自己辛苦开发的并行库,在Python的原生类库中就有了优雅地多的实现。并且还有更优雅的asyncio库!这简直让人累觉不爱。

首先,并行和并发是不同的。100个进程可以在1个CPU上并发地执行,但却能在4个CPU上并行地执行。这就能看出两者的不同。

在实际编程中,有大量的计算或IO是一下子无法结束的。那么如何充分利用各种资源呢?有两个流派:

  • 多进程,多线程(并行)
  • 协程 (并发)

本文实在不能算完整,但汇集了笔者觉得很精髓的不少内容,因此可以认为是一篇综述性文章。

多线程和多进程

先说前者,定义本身是常识就不多说。初级程序员为了让程序变快,于是就狂开线程,不论是IO操作还是计算,能开100个就绝不开50个。线程回收一律不管,这程序只能是玩具。

不过,众所周知Python有GIL(全局解释器锁),任何时候都只有一个线程在工作。那多线程加速还玩个屁啊?!龟叔站出来了,他说:

  • Python在IO操作时,会自动释放GIL,因此IO密集型程序的多线程是有意义的
  • 即使不能多线程,还能多进程,这才是核武器。而Python有非常好用的multiprocessing库解决进程间协同问题。

然而,这些耗时任务,如果不需要知道结果,那还好说(很多程序员直接就把结果写到不同的文件里去,从而避免此问题,太low了)。可是每次都写文件再读出来这太麻烦了。如何收集计算结果呢?

笔者那个工具的做法,是将结果保存到一个队列中,从外部对其进行消费。但Python官方库早就有类似的实现了,多线程和多进程版本分别叫ThreadPoolExecutorProcessPoolExecutor。至于怎么用,出门问度娘。老司机在文章里贴代码太没有逼格了。

好,你度娘上完了。我们会发现他们都在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函数的返回值。至于更详细的信息,可参考

http://www.jianshu.com/p/d09778f4e055

到了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了起来。

更详细的信息,可参考

http://blog.theerrorlog.com/yield-from-in-python-3.html

它有什么用呢?asyncio.

如果你喜欢C#的await和async关键字,则一定会对它的表现印象深刻。异步函数再也不用像js那样做疯狂的回调,顿时代码清晰了很多。这些也是编译器大人的功劳。

详细的可参考:

http://blog.jobbole.com/63897/

看得其实还是晕乎乎的,尽管我自认为对yield和协程有了相对充分的了解却依然如此。

结语

大神说,不要重复造轮子。你会发现之前想做的所有事情,都有远比你想的优雅的多的实现

不过问题在于,用了协程,yield from, asyncio,别人就看不懂我写的代码了,并且不得不升级到py3,可维护性顿时下降很多。因为我发现,就我身边会python的人来说,熟悉且能灵活使用以上那些语义的人不到百分之一。

有任何问题,随时交流。

Python 多线程进程高级指南(二)的更多相关文章

  1. Python 多线程、多进程 (二)之 多线程、同步、通信

    Python 多线程.多进程 (一)之 源码执行流程.GIL Python 多线程.多进程 (二)之 多线程.同步.通信 Python 多线程.多进程 (三)之 线程进程对比.多线程 一.python ...

  2. python进阶-------进程线程(二)

    Python中的进程线程(二) 一.python中的"锁" 1.GIL锁(全局解释锁) 含义: Python中的线程是操作系统的原生线程,Python虚拟机使用一个全局解释器锁(G ...

  3. Python多线程&进程

    一.线程&进程 对于操作系统来说,一个任务就是一个进程(Process),比如打开一个浏览器就是启动一个浏览器进程,打开一个记事本就启动了一个记事本进程,打开两个记事本就启动了两个记事本进程, ...

  4. python多线程和多进程(二)

    ---恢复内容开始--- 一.多进程 1.multiprocessing模块用来开启子进程,并在子进程中执行我们定制的任务(比如函数),该模块与多线程模块threading的编程接口类似. impor ...

  5. Python 多线程 进程与线程相关概念 (一)

    0x00 并行和并发 并行:同时做某些事,可以互不干扰的同一时刻做几件事. 并发:也是同时做某些事,但是强调,同一时刻做了几件事. 0x01 并发的解决: 1)队列.缓冲区: 排队就是队列,先进先出. ...

  6. Python 多线程、多进程 (三)之 线程进程对比、多进程

    Python 多线程.多进程 (一)之 源码执行流程.GIL Python 多线程.多进程 (二)之 多线程.同步.通信 Python 多线程.多进程 (三)之 线程进程对比.多线程 一.多线程与多进 ...

  7. Python 多线程和线程池

    一,前言 进程:是程序,资源集合,进程控制块组成,是最小的资源单位 特点:就对Python而言,可以实现真正的并行效果 缺点:进程切换很容易消耗cpu资源,进程之间的通信相对线程来说比较麻烦 线程:是 ...

  8. Python 多线程、多进程 (一)之 源码执行流程、GIL

    Python 多线程.多进程 (一)之 源码执行流程.GIL Python 多线程.多进程 (二)之 多线程.同步.通信 Python 多线程.多进程 (三)之 线程进程对比.多线程 一.python ...

  9. Python 多线程、进程、协程上手体验

    浅谈 Python 多线程.进程.协程上手体验 前言:浅谈 Python 很多人都认为 Python 的多线程是垃圾(GIL 说这锅甩不掉啊~):本章节主要给你体验下 Python 的两个库 Thre ...

随机推荐

  1. angularJS的一些用法

    AngularJS 事件指令: ng-click/dblclick ng-mousedown/up ng-mouseenter/leave ng-mousemove/over/out ng-keydo ...

  2. Service 之间如何通信?- 每天5分钟玩转 Docker 容器技术(101)

    微服务架构的应用由若干 service 组成.比如有运行 httpd 的 web 前端,有提供缓存的 memcached,有存放数据的 mysql,每一层都是 swarm 的一个 service,每个 ...

  3. 简单模板view调用

    $this->display();//模板名称与当前控制器.当前操作方法的名称不一致 $this->display();//调用当前控制器对应目录指定名称的模板 $this->dis ...

  4. hdu 1151 Air Raid DAG最小边覆盖 最大二分匹配

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1151 题目大意: 城镇之间互相有边,但都是单向的,并且不会构成环,现在派伞兵降落去遍历城镇,问最少最少 ...

  5. CentOS7 nginx简单配置pathinfo模式(ThinkPHP)

    location ~ \.php {    #去掉$ root          H:/PHPServer/WWW; fastcgi_pass   127.0.0.1:9000; fastcgi_in ...

  6. 编写高质量代码—javascript的分层—base层

    base层的功能是为common层和page层提供接口.封装不同浏览器下javaScript的差异,提供统一的接口 1.用getNextNode 函数封装IE和Firefox的差异: 2.透明度:封装 ...

  7. maven jetty struts异常 There is no Action mapped for namespace [/] and action name [] associated with context path

    毕业设计中用maven jetty插件调试时,struts出现这个错误,直接http://localhost:8080 无法进入默认主页,但换tomcat就没问题,最后在这篇文章找到答案 http:/ ...

  8. (转)解决jdk1.8中发送邮件失败(handshake_failure)问题

    解决jdk1.8中发送邮件失败(handshake_failure)问题 作者 zhisheng_tian 2016.08.12 22:44* 字数 1573 阅读 2818评论 6喜欢 9 暑假在家 ...

  9. C#相关知识总结

    字符串相关知识   判断某字符串中包含某个字符,并过滤 if (string.Contains("*")) string = string.Replace('*',' '); // ...

  10. [UWP]了解TypeConverter

    1. 前言 TypeConverter是XAML解释器的幕后功臣,它做了大量工作,从WPF诞生以来,几乎每一次XAML的运作都有它的参与.虽然UWP中TypeConverter已经彻彻底底退居幕后,连 ...