Python多进程学习(一)

栏目: Python · 发布时间: 5年前

内容简介:实战(Python3环境)运行结果:multiprocessing模块是跨平台版本的多进程模块。它提供了一个
前情:这里只是单纯介绍  Python  中的多进程的程序开发,详细的内容还需要看操作系统知识。
复制代码

fork()

  • Python 的 os 模块封装了常见的系统调用,其中就包括 fork() ,可以在 Python 程序中轻松创建子进程,实现多进程。

  • Unix/Linux 操作系统(比如常见的 Mac 咯)提供了一个 fork() 系统调用,它被调用一次,返回两次,因为操作系统自动把当前进程(称为父进程)复制了一份(称为子进程),然后分别在父进程和子进程内返回。

  • 子进程永远返回0,而父进程返回子进程的 ID,因为一个父进程可以 fork 出很多子进程,所以父进程要记下每个子进程的 ID,而子进程只需要调用 getppid() 就可以拿到父进程的 ID。

实战(Python3环境)

import os
print("正在运行的进程是 %s ..." % os.getpid())
pid = os.fork() # 如果是子进程返回0,而父进程返回子进程的ID,有了fork调用,一个进程在接到新任务时就可以复制出一个子进程来处理新任务,常见的Apache服务器就是由父进程监听端口,每当有新的http请求时,就fork出子进程来处理新的http请求。
print("\rpid 是 %s" %pid)
if pid == 0:
    print("子进程是 %s 和父进程是 %s." % (os.getpid(), os.getppid()))
else:
    print("在父进程 %s 中创建了子进程 %s." % (os.getpid(), pid))
复制代码

运行结果:

正在运行的进程是 42322 ...
pid  46501
在父进程 42322 中创建了子进程 46501.
pid  0
子进程是 46501 和父进程是 42322.
复制代码

multiprocessing

multiprocessing模块是跨平台版本的多进程模块。它提供了一个 Process 类来代表一个进程对象。所以不管在 Unix/Linux 操作系统,还是 Windows 操作系统,都可以用 Python 编写多进程的程序。

实战

from multiprocessing import Process
import os

# 子进程要执行的代码
def my_proc(name):
    print("运行子进程 %s." % (os.getpid()))
# 相当于程序执行入口
if __name__=='__main__':
    print("父进程 %s." %os.getpid())
    p = Process(target=my_proc, args=('test',))  # 传入需要执行的函数和函数需要的参数,用start()启动,这种方式比fork()更简单
    print("子进程将要开始.")
    p.start()
    p.join()  # join() 可以等待子进程结束后继续往下执行,通常用于进程间同步
    print("子进程结束.")
复制代码

运行结果:

父进程 42322.
子进程将要开始.
运行子进程 46580.
子进程结束.
复制代码

进程池 Pool

如果要启动大量的子进程,可以用 进程池 创建大量的子进程

实战

from multiprocessing import Pool
import os, time, random

def task(name):  
    print("运行任务 %s (%s)" %(name, os.getpid()))
    start = time.time()
    time.sleep(random.random() * 3)
    end = time.time()
    print("任务 %s 耗时 %.2f 秒" %(name, (end-start)))
    
if __name__ == "__main__":
    print("父进程 %s" %(os.getpid()))
    p = Pool(6)
    for i in range(10):
        p.apply_async(task, args=(i,))
    p.close()
    print("等待所有子进程完毕")
    p.join() # 对 Pool 对象调用 join() 方法会等待所有子进程执行完毕,调用 join() 之前必须先调用 close() ,调用 close() 之后就不能继续添加新的 Process 了
    print("所有子进程执行完毕")
复制代码

运行结果:

父进程 42322
运行任务 2 43382
运行任务 1 43381
运行任务 3 43383
运行任务 0 43380
运行任务 4 43384
运行任务 5 43385
任务 4 耗时 0.05 
运行任务 6 43384
等待所有子进程完毕
任务 5 耗时 0.26 
运行任务 7 43385
任务 1 耗时 0.57 
运行任务 8 43381
任务 7 耗时 0.96 
运行任务 9 43385
任务 8 耗时 1.03 
任务 3 耗时 2.00 
任务 0 耗时 2.07 
任务 6 耗时 2.26 
任务 2 耗时 2.70 
任务 9 耗时 2.61 
所有子进程执行完毕
复制代码

任务 2,1,3,0,4,5是立刻执行的,而其他任务要等待前面某个任务完成后才执行,这是因为 Pool 的大小设置为6,因此,最多同时执行6个进程,Pool 的默认大小是 CPU 的核数

子进程

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

进程间通信

Process之间肯定是需要通信的,操作系统提供了很多机制来实现进程间的通信。Python 的 multiprocessing 模块包装了底层的机制,提供了 QueuePipes 等多种方式来交换数据。

实战

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

# 往 queue 里写内容
def write(q):
    print("写内容的进程: %s" %os.getpid())
    for v in 'ABC':
        print("把 %s 写进队列..." %v)
        q.put(v)
        time.sleep(random.random())
        
# 从 queue 里读内容
def read(q):
    print("读内容的进程: %s" %os.getpid())
    while True:
        v = q.get(True)
        print("从队列中读 %s." %v)

if __name__=="__main__":
    q = Queue()
    pw = Process(target=write, args=(q,))
    pr = Process(target=read, args=(q,))
    pw.start()
    pr.start()
    pw.join() # 等待 pw 结束:
    pr.terminate() # pr 进程里是死循环,只能强行终止
复制代码

运行结果:

写内容的进程: 46049
读内容的进程: 46050
 A 写进队列...
从队列中读 A.
 B 写进队列...
从队列中读 B.
 C 写进队列...
从队列中读 C.
复制代码

本文参考(不分先后顺序):

廖雪峰的官方网站: www.liaoxuefeng.com/wiki/101695…

希望看客老爷打赏些喝茶钱

支付宝
微信

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

程序员成长的烦恼

程序员成长的烦恼

吴亮、周金桥、李春雷、周礼 / 华中科技大学出版社 / 2011-4 / 28.00元

还在犹豫该不该转行学编程?还在编程的道路上摸爬滚打?在追寻梦想的道路上你并不孤单,《程序员成长的烦恼》中的四位“草根”程序员也曾有过类似的困惑。看看油田焊接技术员出身的周金桥是如何成功转行当上程序员的,做过钳工、当过外贸跟单员的李春雷是如何自学编程的,打小在486计算机上学习编程的吴亮是如何一路坚持下来的,工作中屡屡受挫、频繁跳槽的周礼是如何找到出路的。 《程序员成长的烦恼》记录了他们一步一......一起来看看 《程序员成长的烦恼》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

MD5 加密
MD5 加密

MD5 加密工具