Python多进程

参考自:

廖雪峰的Python教程
董伟明的博客

知识点:

  • Process
  • Pool
  • 进程间通信

进程(Process)

对于操作系统来说,一个任务就是一个进程(Process),比如打开一个word就是启动一个word进程。它不止干同一件事情,可以同时进行打字、打印等子任务操作,这些进程内的子任务就是线程(Thread)

  • 单核CPU也可以执行多任务,操作系统轮流
  • 让各个任务交替,Task1执行0.01秒,切换到Task2,Task2执行0.01秒,再切换到Task3,执行0.01秒........这样反复执行下去
  • 真正的并行执行多任务只能在多核CPU上实现

多进程(Multiprocessing)

Multiprocessing模块提供了一个Process类来代表一个进程对象,下面代码演示了创建一个子进程,并等待其结束

  • os.getpid() 获取父进程的ID
  • 创建子进程时,首先创建Process类的实例,再传入一个函数和它的参数
  • 用start()来启动子进程
  • jion() 等待子进程结束后再继续运行下去,用于进程之间的同步

# -*- coding:utf-8 -*-
import os
from multiprocessing import Process


def run_process(name):
    print('Run child process %s(%s)' % (name, os.getpid()))


if __name__ == '__main__':
    print('Run parent process %s' % os.getpid())
    # 创建子进程(创建Process类的实例p),传入一个函数和函数的参数
    p = Process(target=run_process, args=('test', ))
    print('Child process will start!')
    # 启动子进程
    p.start()
    # 等待子进程结束后再运行下去,用于进程间的同步
    p.join()
    print('Child process end!')

执行结果如下:


Run parent process 9156
Child process will start!
Run child process test(1564)
Child process end!

Process finished with exit code 0


Pool

如果要启动大量的子进程,可以使用进程池(Pool)。


# -*- coding:utf-8 -*-
import os
import time
import random
from multiprocessing import Pool


def long_time_task(name):
    print('Run task %s()%s' % (name, os.getpid()))
    start = time.time()
    # random.random():随机生成0~1之间的浮点数
    time.sleep(random.random() * 3)
    end = time.time()
    print('Task %s run %0.2f seconds' % (name, end - start))


if __name__ == '__main__':
    print('Parent process %s' % os.getpid())
    # 创建进程池,大小是4,创建Pool类的实例p,不写子进程数量,默认开到CPU最大
    p = Pool(4)
    # 创建5个子进程,apply_async传入一个函数和它的参数
    for i in range(5):
        p.apply_async(long_time_task, args=(i, ))
    print('Waiting all subprocess done!')
    # join()之前必须先调用close(),调用close()后就不能再添加新的subprocess了
    p.close()
    # 等待所有子进程执行完毕
    p.join()
    print('All subprocess done!')

执行结果如下:


Parent process 13524
Waiting all subprocess done!
Run task 0()14440
Run task 1()15016
Run task 2()8072
Run task 3()3268
Task 0 run 0.28 seconds
Run task 4()14440
Task 3 run 1.14 seconds
Task 2 run 1.54 seconds
Task 1 run 2.11 seconds
Task 4 run 2.82 seconds
All subprocess done!

Pool对象需要调用join()方法会等待所有subprocess执行完毕,调用join()方法之前必须要先调用close()方法,调用close()方法后就不能再添加新的subprocess了

我们看到输出是task0, 1, 2, 3执行了,而task4需要等待某个task执行完毕才能运行,这是因为我们设置了进程池大小为4,它只能同时执行4个子进程,如果不设置进程池大小,就是默认电脑的CPU最大核数

之前用Multiprocess写过多进程爬虫,抓取速度极快,数据量小的甚至可以做到秒抓


进程间通信

Process之间都需要通信,Multiprocessing提供了Queue(队列)Pipe(管道)来进行数据的交换

这里是Queue(队列)为例子,创建两个子进程,一个写数据,一个读数据。创建Queue的实例q,父进程创建队列,分别传递给write和read两个子进程


# -*- coding:utf-8 -*-
import os
import time
import random
from multiprocessing import Process, Queue


def write(q):
    print('Process write to: %s' % os.getpid())
    for value in ['A', 'B', 'C']:
        print('Put %s to queue...' % value)
        # 调用put将value放置队列当中
        q.put(value)
        time.sleep(random.random())


def read(q):
    print('Proecss to read: %s' % os.getpid())
    while True:
        # 将数据从队列中取出
        value = q.get(True)
        print('Get %s from queue' % value)


if __name__ == '__main__':
    # 父进程创建队列,并传递给各个子进程
    q = Queue()
    # 创建write子进程
    pw = Process(target=write, args=(q, ))
    # 创建read子进程
    pr = Process(target=read, args=(q, ))
    # 开启write子进程
    pw.start()
    # 开启read子进程
    pr.start()
    # 等待write子进程结束
    pw.join()
    # read子进程是死循环,需要强制关闭
    pr.terminate()

执行结果如下:

Process write to: 868
Put A to queue...
Proecss to read: 9844
Get A from queue
Put B to queue...
Get B from queue
Put C to queue...
Get C from queue

Process finished with exit code 0


董伟明老师写的多进程教程明显难度要高于廖老师的,用了很多Python的语法糖,需要额外去理解闭包、装饰器、递归,但廖老师的更容易理解

欢迎访问Treehl的博客
Github

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,185评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,445评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,684评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,564评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,681评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,874评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,025评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,761评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,217评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,545评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,694评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,351评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,988评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,778评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,007评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,427评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,580评论 2 349

推荐阅读更多精彩内容

  • 一、进程的概念 相信很多同学都听说过windows、linux,MacOS都是多任务,多用户的操作系统。那什么是多...
    转身后的那一回眸阅读 977评论 0 1
  • 想让python实现多进程(multiprocessing),我们要先区分不同的操作系统的不同之处。 Linux操...
    山有木兮有木兮阅读 8,019评论 0 4
  • 现在, 多核CPU已经非常普及了, 但是, 即使过去的单核CPU, 也可以执行多任务。 CPU执行代码都是顺序执行...
    LittlePy阅读 4,791评论 0 3
  • 进程进程的概念是需要理解的,进程是操作系统中正在运行的一个程序实例,操作系统通过进程操作原语来对其进行调度。操作系...
    zhile_doing阅读 489评论 0 0
  • 进程的基本概念 进程是程序的一次执行,每个进程都有自己的地址空间,内存,数据栈以及其他记录其运行轨迹的辅助数据。多...
    XYZeroing阅读 1,203评论 0 13