创建进程的常用方式

自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm=1001.2014.3001.5501

在Python中有多个模块可以创建进程,比较常用的有os.fork()函数、multiprocessing模块和Pool进程池。由于os.fork()函数只适用于Unix/Linux/Mac系统上运行,在Windows操作系统中不可用,所以本章重点介绍multiprocessing模块和Pool进程池这2个跨平台模块。

1  使用multiprocessing模块创建进程

multiprocessing模块提供了一个Process类来代表一个进程对象,语法如下:

Process([group [, target [, name [, args [, kwargs]]]]])

Process类的参数说明如下:

l  group:参数未使用,值始终为None。

l  target:表示当前进程启动时执行的可调用对象。

l  name:为当前进程实例的别名。

l  args:表示传递给target函数的参数元组。

l  kwargs:表示传递给target函数的参数字典。

例如,实例化Process类,执行子进程,代码如下: 

from multiprocessing import Process         # 导入模块

# 执行子进程代码

def test(interval):

    print('我是子进程')

# 执行主程序

def main():

    print('主进程开始')

    p = Process(target=test,args=(1,))      # 实例化Process进程类

    p.start()                               # 启动子进程

    print('主进程结束')

if __name__ == '__main__':

    main()

运行结果如下:

主进程开始

主进程结束

我是子进程

注意:由于IDLE自身的问题,运行上述代码时,不会输出子进程内容,所以使用命令行方式运行Python代码,即在文件目录下,用“python + 文件名”方式,如图3所示。

图3  使用命令行运行python文件

上述代码中,先实例化Process类,然后使用p.start()方法启动子进程,开始执行test()函数。
Process的实例p常用的方法除start()外,还有如下常用方法:

l  is_alive():判断进程实例是否还在执行。

l  join([timeout]):是否等待进程实例执行结束,或等待多少秒。

l  start():启动进程实例(创建子进程)。

l  run():如果没有给定target参数,对这个对象调用start()方法时,就将执行对象中的run()方法。

l  terminate():不管任务是否完成,立即终止。

Process类还有如下常用属性:

l  name:当前进程实例别名,默认为Process-N,N为从1开始递增的整数。

l  pid:当前进程实例的PID值。

图标 (35)

  实例01  创建两个子进程,并记录子进程运行时间

下面通过一个简单示例演示Process类的方法和属性的使用,创建2个子进程,分别使用os模块和time模块输出父进程和子进程的ID以及子进程的时间,并调用Process类的name和pid属性,代码如下:

# -*- coding:utf-8 -*-

from multiprocessing import Process

import time

import os

# 两个子进程将会调用的两个方法

def  child_1(interval):

    print("子进程(%s)开始执行,父进程为(%s)" % (os.getpid(), os.getppid()))

    t_start = time.time()                   # 计时开始

    time.sleep(interval)                    # 程序将会被挂起interval秒

    t_end = time.time()                     # 计时结束

    print("子进程(%s)执行时间为'%0.2f'秒"%(os.getpid(),t_end - t_start))

def  child_2(interval):

    print("子进程(%s)开始执行,父进程为(%s)" % (os.getpid(), os.getppid()))

    t_start = time.time()                   # 计时开始

    time.sleep(interval)                    # 程序将会被挂起interval秒

    t_end = time.time()                     # 计时结束

    print("子进程(%s)执行时间为'%0.2f'秒"%(os.getpid(),t_end - t_start))

if __name__ == '__main__':

    print("------父进程开始执行-------")

    print("父进程PID:%s" % os.getpid())                 # 输出当前程序的PID

    p1=Process(target=child_1,args=(1,))                 # 实例化进程p1

    p2=Process(target=child_2,name="mrsoft",args=(2,))    # 实例化进程p2

    p1.start()                          # 启动进程p1

    p2.start()                          # 启动进程p2

    # 同时父进程仍然往下执行,如果p2进程还在执行,将会返回True

    print("p1.is_alive=%s"%p1.is_alive())

    print("p2.is_alive=%s"%p2.is_alive())

    # 输出p1和p2进程的别名和PID

    print("p1.name=%s"%p1.name)

    print("p1.pid=%s"%p1.pid)

    print("p2.name=%s"%p2.name)

    print("p2.pid=%s"%p2.pid)

    print("------等待子进程-------")

    p1.join()                         # 等待p1进程结束

    p2.join()                         # 等待p2进程结束

    print("------父进程执行结束-------")

上述代码中,第一次实例化Process类时,会为name属性默认赋值为“Process-1”,第二次则默认为“Process-2”,但是由于在实例化进程p2时,设置了name属性为“mrsoft”,所以p2.name的值为“mrsoft”而不是“Process-2”。程序运行流程示意图如图4所示,运行结果如图5所示。

图4  运行流程示意图

图5  创建2个子进程

注意:读者运行时,进程的PID值会与图5不同,这与电脑有关,读者不必在意。

2  使用Process子类创建进程

对于一些简单的小任务,通常使用Process(target=test)方式实现多进程。但是如果要处理复杂任务的进程,通常定义一个类,使其继承Process类,每次实例化这个类的时候,就等同于实例化一个进程对象。下面,通过一个示例来学习一下如何通过使用Process子类创建多个进程。

图标 (35)

  实例02  使用Process子类创建两个子进程,并记录子进程运行时间

使用Process子类方式创建2个子进程,分别输出父、子进程的PID,以及每个子进程的状态和运行时间,代码如下:

# -*- coding:utf-8 -*-

from multiprocessing import Process

import time

import os

# 继承Process类

class SubProcess(Process):

    # 由于Process类本身也有__init__初始化方法,这个子类相当于重写了父类的这个方法

    def __init__(self,interval,name=''):

        Process.__init__(self)       # 调用Process父类的初始化方法

        self.interval = interval     # 接收参数interval

        if name:                     # 判断传递的参数name是否存在

            self.name = name    # 如果传递参数name,则为子进程创建name属性,否则使用默认属性

    # 重写了Process类的run()方法

    def run(self):

        print("子进程(%s) 开始执行,父进程为(%s)"%(os.getpid(),os.getppid()))

        t_start = time.time()

        time.sleep(self.interval)

        t_stop = time.time()

        print("子进程(%s)执行结束,耗时%0.2f秒"%(os.getpid(),t_stop-t_start))

if __name__=="__main__":

    print("------父进程开始执行-------")

    print("父进程PID:%s" % os.getpid())        # 输出当前程序的ID

    p1 = SubProcess(interval=1,name='mrsoft')

    p2 = SubProcess(interval=2)

    # 对一个不包含target属性的Process类执行start()方法,就会运行这个类中的run()方法

    # 所以这里会执行p1.run()

    p1.start()                      # 启动进程p1

    p2.start()                      # 启动进程p2

    # 输出p1和p2进程的执行状态,如果真正进行,返回True;否则返回False

    print("p1.is_alive=%s"%p1.is_alive())

    print("p2.is_alive=%s"%p2.is_alive())

    # 输出p1和p2进程的别名和PID

    print("p1.name=%s"%p1.name)

    print("p1.pid=%s"%p1.pid)

    print("p2.name=%s"%p2.name)

    print("p2.pid=%s"%p2.pid)

    print("------等待子进程-------")

    p1.join()                     # 等待p1进程结束

    p2.join()                     # 等待p2进程结束

    print("------父进程执行结束-------")

上述代码中,定义了一个SubProcess子类,继承multiprocess.Process父类。SubProcess子类中定义了2个方法:__init__()初始化方法和run()方法。在__init()__初识化方法中,调用multiprocess.Process父类的__init__()初始化方法,否则父类初始化方法会被覆盖,无法开启进程。此外,在SubProcess子类中并没有定义start()方法,但在主进程中却调用了start()方法,此时就会自动执行SubPorcess类的run()方法。运行结果如图6所示。

图6  使用Porcess子类创建进程

3  使用进程池Pool创建进程

在16.2.1小节和16.2.2小节中,我们使用Process类创建了2个进程。如果要创建几十个或者上百个进程,则需要实例化更多个Process类。有没有更好的创建进程的方式解决这类问题呢?答案就是使用multiprocessing模块提供的Pool类,即Pool进程池。

为了更好的理解进程池,可以将进程池比作水池,如图7所示。我们需要完成放满10个水盆的水的任务,而在这个水池中,最多可以安放3个水盆接水,也就是同时可以执行3个任务,即开启3个进程。为更快完成任务,现在打开3个水龙头开始放水,当有一个水盆的水接满时,即该进程完成1个任务,我们就将这个水盆的水倒入水桶中,然后继续接水,即执行下一个任务。如果3个水盆每次同时装满水,那么在放满第9盆水后,系统会随机分配1个水盆接水,另外2个水盆空闲。

图7  进程池示意图

接下来,先来了解一下Pool类的常用方法。常用方法及说明如下:

l  apply_async(func[, args[, kwds]]) :使用非阻塞方式调用func()函数(并行执行,堵塞方式必须等待上一个进程退出才能执行下一个进程),args为传递给func()函数的参数列表,kwds为传递给func()函数的关键字参数列表。

l  apply(func[, args[, kwds]]):使用阻塞方式调用func()函数。

l  close():关闭Pool,使其不再接受新的任务。

l  terminate():不管任务是否完成,立即终止。

l  join():主进程阻塞,等待子进程的退出, 必须在close或terminate之后使用。

在上面的方法提到apply_async()使用非阻塞方式调用函数,而apply()使用阻塞方式调用函数。那么什么又是阻塞和非阻塞呢?在图8中,分别使用阻塞方式和非阻塞方式执行3个任务。如果使用阻塞方式,必须等待上一个进程退出才能执行下一个进程,而使用非阻塞方式,则可以并行执行3个进程。

图8  阻塞与非阻塞示意图

图标 (35)

  实例03  使用进程池创建多进程

下面通过一个示例演示一下如何使用进程池创建多进程。这里模拟水池放水的场景,定义一个进程池,设置最大进程数为3。然后使用非阻塞方式执行10个任务,查看每个进程执行的任务。具体代码如下: 

# -*- coding=utf-8 -*-

from multiprocessing import Pool

import os, time

def task(name):

    print('子进程(%s)执行task %s ...' % ( os.getpid() ,name))

    time.sleep(1)                       # 休眠1秒

if __name__=='__main__':

    print('父进程(%s).' % os.getpid())

    p = Pool(3)                    # 定义一个进程池,最大进程数3   

    for i in range(10):                       # 从0开始循环10次   

        p.apply_async(task, args=(i,))      # 使用非阻塞方式调用task()函数  

    print('等待所有子进程结束...')

    p.close()                       # 关闭进程池,关闭后p不再接收新的请求

    p.join()                        # 等待子进程结束

    print('所有子进程结束.')

运行结果如图9所示,从图9可以看出PID为11488的子进程执行了4个任务,而其余2个子进程分别执行了3个任务。

图9  使用进程池创建进程

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/30452.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

0617,递归问题(详细——好好好一入递归深似海)

目录 第七章(函数)思维导图总结:递归三问 01,电影院问题 理解递归的执行过程 02,FIBNACCI数列 不是说具有递归结构的问题,就可以用递归求解——存在大量的重复计算 法一:自顶向下求解 BUG…

ruoyi框架第二天,自定义接口,在若依框架显示数据

书接上文,搭建好若依,并且创建自己想要的模块。 让ruoyi框架显示自己想要的模块。 今天,我们就要自定义接口,模仿ruoyi框架收发数据模式,来创建自己的模块。 我们创建好自己想要的接口,我这个是无参的查…

【Java】已解决java.util.EmptyStackException异常

文章目录 一、问题背景二、可能出错的原因三、错误代码示例四、正确代码示例五、注意事项 已解决java.util.EmptyStackException异常 一、问题背景 java.util.EmptyStackException是Java在使用java.util.Stack类时可能会遇到的一个异常。这个异常通常在尝试从空的栈中弹出&am…

四连杆机构运动学仿真 | Matlab源码+理论文本【超详细】

【程序简介】💻🔍 本程序通过matlab实现了四连杆机构的运动学仿真编程,动态展现了四连杆机构的角位移、角速度和角加速度的时程曲线,除了程序本身,还提供了机构运动学详细的公式推导文档,从而帮助大家更好…

2024年化学、能源与核工程国际会议(ICCENE 2024)

2024年化学、能源与核工程国际会议(ICCENE 2024) 2024 International Conference on Chemical, Energy and Nuclear Engineering (ICCENE 2024) 会议地点:三亚,中国 网址:www.iccene.com 邮箱: iccenesub-conf.com 投稿主题请注明:ICCEN…

【面试题】Spring常见面试题整理2024(全是干货!!!)

备战实习,会定期给大家整理常考的面试题,大家一起加油! 🎯 注意:文章若有错误的地方,欢迎评论区里面指正 🍭 系列文章目录 【面试题】MySQL常见面试题总结【面试题】面试题分享之JVM篇【面试题…

信息学奥赛初赛天天练-29-CSP-J2022阅读程序-掌握递归、递推、动态规划、二分与极值函数应用

PDF文档公众号回复关键字:20240619 2022 CSP-J 阅读程序2 阅读程序(判断题1.5分 选择题3分 共计40分 ) 01 #include <algorithm> 02 #include <iostream> 03 #include <limits> 04 05 using namespace std; 06 07 const int MAXN 105; 08 const int MAX…

C/C++ string模拟实现

1.模拟准备 1.1因为是模拟string&#xff0c;防止与库发生冲突&#xff0c;所以需要命名空间namespace隔离一下&#xff0c;我们来看一下基本内容 namespace yx {class string{private://char _buff[16]; lunix下小于16字节就存buff里char* _str;size_t _size;size_t _capac…

2713. 矩阵中严格递增的单元格数

题目 给定一个 m x n 的整数矩阵 mat&#xff0c;我们需要找出从某个单元格出发可以访问的最大单元格数量。移动规则是可以从当前单元格移动到同一行或同一列的任何其他单元格&#xff0c;但目标单元格的值必须严格大于当前单元格的值。需要返回最大可访问的单元格数量。 示例…

服务器流量收发测试

文章目录 一、概述二、实现方式一&#xff1a;编码1. 主要流程2. 核心代码3. 布署 三、实现方式二&#xff1a;脚本1.脚本编写2. 新增crontab任务 四、查看结果 一、概述 我们在安装vnStat、wondershaper便想通过实际的数据收发来进行测试。 二、实现方式一&#xff1a;编码 …

C#客户端

控件 打开链接 Socket socket; // 打开连接 private void button1_Click(object sender, EventArgs e) {button1.Enabled false;button2.Enabled true;//1 创建socket客户端对象socket new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);// 2…

ChatGPT 提示词技巧一本速通

目录 一、基本术语 二、提示词设计的基本原则 三、书写技巧 2.1 赋予角色 2.2 使用分隔符 2.2 结构化输出 2.3 指定步骤 2.4 提供示例 2.5 指定长度 2.6 使用或引用参考文本 2.7 提示模型进行自我判断 2.8 思考问题的解决过程 ​编辑 2.10 询问是否有遗漏 2.11 …

Studio One 6中文官网下载-Studio One软件下载-音乐编曲软件下载安装

​众多使用者向我们证明了轨道预设保存并调用您喜欢的曲目设置的快照&#xff0c;将您的工作流程效率升级到最新水平&#xff01;存储指定轨道或频道的每项设置&#xff0c;以便即时调用&#xff0c;即使对于多个选定的曲目/频道也同样支持&#xff0c;轨道预设可存储轨道延迟、…

如何将本地代码上传到git上面

精简步骤&#xff1a; git init git add . git commit -m "first init" git remote add origin 远程仓库地址 git push -u origin master 目录 1、初始化本地仓库 2、添加所有文件到本地仓库 3、提交更改到本地仓库 4、添加github仓库作为远程仓库 5、推送更改…

国际期货投机交易的常见操作方法:

一、在开仓阶段&#xff0c;入市时机的选择&#xff1a; &#xff08;1&#xff09;通过基本分析法&#xff0c;判断市场处于牛市还是熊市 开仓阶段&#xff0c;入市时机的选择&#xff1a;当需求增加、供给减少&#xff0c;此时价格上升&#xff0c;买入期货合约&#xff1b…

# 消息中间件 RocketMQ 高级功能和源码分析(五)

消息中间件 RocketMQ 高级功能和源码分析&#xff08;五&#xff09; 一、 消息中间件 RocketMQ 源码分析&#xff1a;NameServer 路由元数据 1、消息中间件 RocketMQ 中&#xff0c;NameServer 路由管理 NameServer 的主要作用是为消息的生产者和消息消费者提供关于主题 To…

一个小的画布Canvas页面,记录点的轨迹

Hello大家好&#xff0c;好久没有更新了&#xff0c;最近在忙一些其他的事&#xff0c;今天说一下画布canvas&#xff0c;下面是我的代码&#xff0c;实现了一个点从画布的&#xff08;0,0&#xff09;到&#xff08;canvas.width&#xff0c;canvas.height&#xff09;的一个实…

60.指针数组和数组指针

一.指针数组 指针数组是一个数组&#xff0c;在指针数组中存放的是指针变量。 定义一个指针数组p int *p[5]; 内存模型如下&#xff1a; 指针数组的初始化 #include <stdio.h>int main(void) {int a1;int b2;int c3;int i;int *p[3] {&a,&b,&c};for(i0…

椭圆的标准方程与协方差矩阵的特征值和特征向量的关系

椭圆的标准方程与协方差矩阵的特征值和特征向量的关系 flyfish 单位圆 &#xff1a;单位圆表示在标准正交基下的分布。 椭圆 &#xff1a;通过协方差矩阵的特征向量和特征值变换得到的椭圆&#xff0c;表示数据在新的坐标系下的分布。 特征向量 &#xff1a;红色箭头表示特征…

Android sensor列表和访问记录

命令: dumpsys sensorservice 1.dumpsys sensorservice查看最近申请记录 dumpsys sensorservice命令输出Previous Registrations. Previous Registrations: 23:07:43 0x00000008 pid16587 uid10397 packagecom.start.testdemo.ui.udfp.fql.XsqFQLActivity samplingPeriod66…