Python的多进程和消息队列

Python的多进程和消息队列

对于Python这种动态语言而言,多进程是最快提升效率的办法。对于绝大部分项目,实质上多进程加上协程操作已经可以满足常规的并发需求了。由此构建的web服务器也可以满足大部分的需求。我们首先来看多进程和消息队列的示例。

from multiprocessing import Process, Queue

def test1(que):
    print('我是子进程1')
    testmsg = '我是在《子进程1》内存空间中的信息'
    que.put(testmsg)
def test2(que):
    print('我是子进程2')
    testmsg = '我是在《子进程2》内存空间中的信息'
    que.put(testmsg)

def main(que):
    print('主进程开始')
    p1 = Process(target = test1 ,args = (que,))
    p2 = Process(target= test2, args=(que,))
    p1.start()
    testmsg = que.get()
    print(testmsg)
    p2.start()
    testmsg= que.get()
    print(testmsg)
    p1.join()
    p2.join()
    print('主进程结束')
    
if __name__ == '__main__':
    que = Queue()
    main(que)

多进程使用队列通讯在程序\text{\ref{multiprocess_queue}}中,我们示例了一个最简单的多进程(3进程)的通讯过程。注意在test子进程和main主进程中都有队列que作为参量。而消息队列的方法一般只用到两个,就是put和get。put是将内容推入消息队列,get则是取出。实现多进程实例需要使用到multiprocessing 这个模块中的Process类。它会将函数(也可以是对象)和参量作为target 和 args 糅合成一个进程对象。然后用start()方法来启动进程。另一个值得注意的是join()方法,它实际上是将子进程包含在主进程中的方法。如果不使用join()方法,那么各个进程之间就是独立的而且会乱七八糟输出。如果你希望主进程等待子进程结束后才结束,必须使用join()方法。

上面的多进程适合简单无需进程控制的任务,因为每个进程在运行的是一个函数。这样的编程范例往往是把耗时较久的任务单独开一个进程来执行,中间一般只需要将任务执行情况向主进程通过消息队列回报。但绝大多数时候,我们需要对进程进行高级控制。比如读取进程id,挂起进程(使用psutil包的suspend方法),恢复进程(使用psutil包的resume方法)。此时用函数来自己写进程的控制就很费时费力。另一方面,不同进程往往对应着不同的功能,所以用类能够使得编程更清晰。所以更一般的多进程编程范例是将子进程写成进程类。但如果所有的进程都做同一件事,实际上更扁平的设计是使用函数编程。具体还是看需求来设计。

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

class SubProcess(Process):
    def __init__(self, que):
        Process.__init__(self)
        self.que = que
    def run(self):
        print('我是子进程1, 进程id为:%s'%str(os.getpid()))
        p = psutil.Process()#留空表示当前进程
        self.que.put({'process_id': os.getpid(), "process_num":1}) 
        # 推送进程id
        for i in range(10):
            print(i)
            self.que.put(i)
            time.sleep(1)
        self.que.put({"create_time": p.create_time()})

if __name__=="__main__":
    print('主进程开始')
    que1 = Queue()
    p1 = SubProcess(que1)
    p1.start()
    sub_pid = que1.get()['process_id']# 子进程id
    p_sub = psutil.Process(sub_pid)
    for j in range(10):
        i_value = que1.get()
        print('子程序%s运行到了第%d个步骤'%(sub_pid, i_value+1))
    p1.join()
    subproc_ctime = que1.get()
    print("子进程%s"%(str(sub_pid)) + '运行了%f秒'
          %(time.time()-subproc_ctime['create_time']) +'\n 已完成工作~' )
    print('主进程结束')

有时候我们需要用进程池来快速建立多个进程。比如如果我们使用的网站服务器是Apache,那么对于多个连接传输请求,往往是建立多个进程来实现并发。注意,这种并发没有上下文关联,更不存在递归调用。所以特别适合处理独立连接的并发。

进程池提供了阻塞和非阻塞的两种方式。

阻塞方式看上去好像没有用,因为阻塞会完全使用不了多进程并发。而且阻塞完了还会需要进程切换,这看似是低效率的。但实际上,并非如此。因为我们往往在主进程进行调度操作,而子进程进行费时的数据处理操作。所以把任务合理分配为调度任务和数据处理任务会大大加速程序的运行效率。即,我们在主进程上分配大量琐碎的调度和轻量级的数据处理。而在子进程上分配重量级的数据处理问题。甚至可以建立一个次主进程专门负责调度,而其他进程则负责数据处理或者通讯。

from multiprocessing import Pool
import os,time
def task(param):
    start_time = time.time()
    sum = 0
    for i in range((param-1)*20,param*20):
        sum += i
        time.sleep(0.2)
    proc_time= time.time()-start_time
    print("进程%d执行了%.2f秒,结果是%d"%(os.getpid(),proc_time,sum))

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