本文是如何《优雅地实现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. 常用IO按位操作

    PORTD |= (1 << op)           //位置高PORTD &= ~(1 << op)          //位置低PORTD ^= (1 < ...

  2. JS 函数节流和去抖

    1.什么是节流和去抖? 节流.就是拧紧水龙头让水少流一点,但是不是不让水流了.想象一下在现实生活中有时候我们需要接一桶水,接水的同时不想一直站在那等着,可能要离开一会去干一点别的事请,让水差不多流满一 ...

  3. 01---Spring框架

    Spring框架简介及官方压缩包目录介绍 工厂模式 Spring环境搭建 IoC详解 Spring创建Bean的三种方式(包含两种工厂方式) scope属性讲解 DI详解 Spring中几种注入方式 ...

  4. javascript设计模式——单例模式

    前面的话 单例模式是指保证一个类仅有一个实例,并提供一个访问它的全局访问点. 单例模式是一种常用的模式,有一些对象往往只需要一个,比如线程池.全局缓存.浏览器中的window对象等.在javaScri ...

  5. Codeforces Gym 101521A Shuttle Bus

    题意:给定一个2*N的方格,从左上角开始走,有些格子不能走,问能否一次遍历所有能走的方格 在Gym上看到一场香港的比赛,很好奇就去看了一下,发现第一题很有趣,并且很水,似乎讨论一下奇偶性就行了,然后. ...

  6. Qt快速上手(学习笔记四)

    拖了大半年,今天终于有更新了...我自己都不好意思,最近太忙了! 今天讲一下:QML语法 一 概述 QML是一种专门用于构建用户界面的编程语言,它允许用户构建高性能,具有流畅特效的可视化应用程序,QM ...

  7. 好好写代码吧,没事别瞎B去创业!

    知乎上看到这个问题 正好最近想写篇关于此的文章,于是就回答了一波. 也贴到这里来,回答如下 : 本问题简直为我量身定制,做为一个正在创业中的苦逼少年,说说我是如何从鼓吹怂恿身边人创业转换成反对创业的. ...

  8. onunload事件和onbeforeunload事件

    记录知识点背景:在做一个h5项目时,在统计事件时有这样一个需求, 希望能统计到用户是从第几页离开的,用到了这个知识点.在此记录. window.onunload 1.定义和用法 onunload事件在 ...

  9. 是否是有效的dom节点--轮子代码

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"/> <title> ...

  10. 【004】【JVM——垃圾收集算法】

     Java虚拟机学习总结文件夹 垃圾收集算法 垃圾收集算法的实现涉及大量的程序细节,并且各个平台的虚拟机操作内存的方法又各不同样,介绍几种垃圾收集算法的思想及其发展过程. 标记-清除算法 垃圾收集 ...