python之多进程

要让python实现多进程「multiprocessing」。我们先来了解操作系统相关知识。
Unix 和 Linux 操作系统提供了一个 fork() 函数系统调用,它非常特殊。普通的函数,调用一它次,执行一次,但是 fork() 函数调用一次执行两次,因为操作系统自动把当前进程「称为父进程」复制了一份「称为子进程」,然后,分别在子进程和父进程中执行。
子进程永远返回0,而父进程返回子进程的 ID。这样做的理由是,一个父进程可以 fork() 多个子进程,所以父进程要记下所有子进程的 ID,而子进程只要调用 getppid() 就可以拿到父进程的 ID。
python中 os 模块封装了常见的系统调用,其中就包括 fork(),可以在python程序中轻松创建子程序:

import os

print('Process (%s) start ...' % os.getpid())
#Only work on Unix/linux/Mac
#不能在Windows平台上运行
pid = os.fork()
if pid == 0:
    print('I am child process (%) and my parent is %s.' % (os.getpid(),os.getppid()))
else:
    print('I (%) just created a child process (%).' % (os.getpid(),pid))

运行结果:

Process (876) start...
I (876) just created a child process (877).
I am child process (877) and my parent is 876.

由于 Windows 平台下没有 fork() 函数调用,所以代码没有办法在 Windows平台下运行。
有了 fork 调用,一个进程在接到任务的时候就可以复杂出来一个子进程来处理新任务,常见的 Apache 服务器就是由父进程监听端口,每当有新的 http 请求时,就 fork 出新的子进程来处理新的 http 请求。

multiprocessing「多进程」

如果你想写多进程的服务程序,Unix/Linux 平台最好了,当然也可以在 Windows 平台下来编写,因为 python 跨平台。multiprocessing 模块就是跨平台版本的多进程模块。
multiprocessing 模块提供了一个 Process 类来代表一个进程对象,下面一个例子用来演示启动一个子进程并等待结束的例子:

import os
from multiprocessing import Process

#子进程要执行的代码
def run_proc(name):
    print('Run child process %s (%s)' % (name,os.getpid()))

if __name__ == '__main__':
    print('parent process %s' % os.getpid())
    p = Process(target=run_proc,args=('test',))#创建子程序
    print('Child process will start')
    p.start()#子程序开始执行
    p.join()
    print('Child process end.')
  • 创建子程序时,只需要传入一个执行的函数和函数的参数。
  • 创建一个 Procsess 实例,用 start() 方式开启,这样创建的进程比 fork 还简单。
  • join() 方法可以等jinc子进程执行完后再继续往下运行,通常用于进程之间的同步。
    Pool
    如果想要启动大量的子进程,可以用进程池的方式批量创建子进程。
import os,time,random
from multiprocessing import Pool

def long_time_task(name):
    print('Run task %s (%s)...' % (name,os.getpid()))
    start = time.time()
    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())
    p = Pool(4)
    for i in range(5):
        p.apply_async(long_time_task,args=(i,))
    print('Waiting for all subprocess done...')
    p.close()
    p.join()
    print('All subprocess done')

执行结果:

Parent process 7600.
Waiting for all subprocess done...
Run task 0 (11392)...
Run task 1 (6432)...
Run task 2 (10768)...
Run task 3 (5116)...
Task 0 run 0.03 seconds.
Run task 4 (11392)...
Task 3 run 1.42 seconds.
Task 1 run 1.77 seconds.
Task 4 run 2.59 seconds.
Task 2 run 2.93 seconds.
All subprocess done

Process finished with exit code 0
  • 对Pool调用 join() 方法会等所用子进程执行完毕,调用 join() 之前一定要调用 close() 调用 close() 之后不能在有新的process
  • 程序的输出结果显示 task 0、1、2、3 是同时执行的,而 task 4 是等前四个执行完毕才执行,这是因为,进程池在我的电脑上是4。,因此最多执行四个进程,这是 Pool 有意设计的限制,并不是操作系统的限制,如果你改成
p = Pool(5)

就可以同时跑 5 个进程。

子进程

很多时候,子进程并不是本身,热是一个外部的进程。我们创建了子进程之后,还要控制进程的输入和输出。
subprocess 模块可以让我们非常方便的启动一个子进程,然后控制输入和输出。

这一部分未完待续


进程间的通信

Process 间肯定是要通信的,操作系统提供了很多机制来实现进程间的通信,python 中的 multiprocessing 模块包装了底层的机制,提供了 Queue、Pipes 等多种方法来交换数据。
我们以 Queue 为例,在父进程中创建两个子进程,一个往 Queue 里写数据,一个从 Queue 中读数据。

from multiprocessing import Queue,Process
import os,time,random

#写数据进程执行的代码
def write(q):
    print('Process to write : %s' % os.getpid())
    for value in ['A','B','C']:
        print('Put %s queue...' % value)
        q.put(value)
        time.sleep(random.random())

#读数据执行的代码
def read(q):
    print('Process to read : %s' % os.getpid())
    while True:
        value = q.get(True)
        print('Get %s from queue.' % value)

if __name__ == '__main__':
    #父进程创建Queue,并传给各个子进程
    q = Queue()
    pw = Process(target=write,args=(q,))
    pr = Process(target=read,args=(q,))
    #启动子程序pw,写入:
    pw.start()
    #启动子程序pr,读取:
    pr.start()
    #等待pw结束:
    pw.join()
    #pr进程是死循环,无法等待它结束,只能强行终止。
    pr.terminate()

运行结果

Process to read : 8416
Process to write : 12840
Put A queue...
Get A from queue.
Put B queue...
Get B from queue.
Put C queue...
Get C from queue.

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

推荐阅读更多精彩内容

  • 环境:win7+python2.7 一直想学习多进程或多线程,但之前只是单纯看一点基础知识还有简单的介绍,无法理解...
    今天芒种阅读 9,250评论 2 19
  • 1.进程 1.1多线程的引入 现实生活中 有很多的场景中的事情是同时进行的,比如开车的时候手和脚共同来驾驶汽车,再...
    TENG书阅读 500评论 0 0
  • 一、进程的概念 相信很多同学都听说过windows、linux,MacOS都是多任务,多用户的操作系统。那什么是多...
    转身后的那一回眸阅读 983评论 0 1
  • 余生别慌张, 找一个人慢慢相爱。 他看你时眼神温柔, 愿意陪你做很多事、 说很多话、走很多路。 然后,就此一生。 ...
    刘慧amy阅读 703评论 0 2
  • 20170808 遇见真实的自己 那时候,性格很是强,把自己张结的黄干黑瘦。心事重重地迎接着每一天,每个人。自尊心...
    灵滴阅读 264评论 0 2