深入Python多进程编程基础

python多进程基础教程:python并发编程之多进程 文章目录一 multiprocessing模块介绍二 Process类的介绍三 Process类的使用四 守护进程五 进程同步(锁)六 队列(推荐使用)七 管道八 共享数据九 信号量(了解)十 事件(了解)十一 进程池回掉函数: 一 multiprocessing模块介绍 python中的多线程无法利用多核优势,如果想要充分地使用多核CPU的资源(os.cpu_count()查看),在python... 阅读详情

多进程编程知识是Python程序员进阶高级的必备知识点,我们平时习惯了使用multiprocessing库来操纵多进程,但是并不知道它的具体实现原理。下面我对多进程的常用知识点都简单列了一遍,使用原生的多进程方法调用,帮助读者理解多进程的实现机制。代码跑在linux环境下。没有linux条件的,可以使用docker或者虚拟机运行进行体验。

docker pull python:2.7

生成子进程

Python生成子进程使用os.fork(),它将产生一个子进程。fork调用同时在父进程和主进程同时返回,在父进程中返回子进程的pid,在子进程中返回0,如果返回值小于零,说明子进程产生失败,一般是因为操作系统资源不足。

import os
def create_child():
    pid = os.fork()
    if pid > 0:
        print 'in father process'
        return True
    elif pid == 0:
        print 'in child process'
        return False
    else:
        raise

生成多个子进程

我们调用create_child方法多次就可以生成多个子进程,前提是必须保证create_child是在父进程里执行,如果是子进程,就不要在调用了。

# coding: utf-8
# child.py
import os

def create_child(i):
    pid = os.fork()
    if pid > 0:
        print 'in father process'
        return pid
    elif pid == 0:
        print 'in child process', i
        return 0
    else:
        raise

for i in range(10):  # 循环10次,创建10个子进程
    pid = create_child(i)
    # pid==0是子进程,应该立即退出循环,否则子进程也会继续生成子进程
    # 子子孙孙,那就生成太多进程了
    if pid == 0:
        break

运行python child.py,输出

in father process
in father process
in child process 0
in child process 1
in father process
in child process 2
in father process
in father process
in child process 3
in father process
in child process 4
in child process 5
in father process
in father process
in child process 6
in child process 7
in father process
in child process 8
in father process
in child process 9

进程休眠

使用time.sleep可以使进程休眠任意时间,单位为秒,可以是小数

import time
for i in range(5):
    print 'hello'
    time.sleep(1)  # 睡1s

杀死子进程

使用os.kill(pid, sig_num)可以向进程号为pid的子进程发送信号,sig_num常用的有SIGKILL(暴力杀死,相当于kill -9),SIGTERM(通知对方退出,相当于kill不带参数),SIGINT(相当于键盘的ctrl+c)。

# coding: utf-8
# kill.py

import os
import time
import signal


def create_child():
    pid = os.fork()
    if pid > 0:
        return pid
    elif pid == 0:
        return 0
    else:
        raise


pid = create_child()
if pid == 0:
    while True:  # 子进程死循环打印字符串
        print 'in child process'
        time.sleep(1)
else:
    print 'in father process'
    time.sleep(5)  # 父进程休眠5s再杀死子进程
    os.kill(pid, signal.SIGKILL)
    time.sleep(5)  # 父进程继续休眠5s观察子进程是否还有输出

运行python kill.py,我们看到控制台输出如下

in father process
in child process
# 等1s
in child process
# 等1s
in child process
# 等1s
in child process
# 等1s
in child process
# 等了5s

说明os.kill执行之后,子进程已经停止输出了

僵尸子进程

在上面的例子中,os.kill执行完之后,我们通过ps -ef|grep python快速观察进程的状态,可以发现子进程有一个奇怪的显示<defunct>

root        12     1  0 11:22 pts/0    00:00:00 python kill.py
root        13    12  0 11:22 pts/0    00:00:00 [python] <defunct>

待父进程终止后,子进程也一块消失了。那<defunct>是什么含义呢?

收割子进程

如果彻底干掉僵尸进程?父进程需要调用waitpid(pid, options)函数,「收割」子进程,这样子进程才可以灰飞烟灭。waitpid函数会返回子进程的退出状态,它就像子进程留下的临终遗言,必须等父进程听到后才能彻底瞑目。

# coding: utf-8
import os
import time
import signal
def create_child():
    pid = os.fork()
    if pid > 0:
        return pid
    elif pid == 0:
        return 0
    else:
        raise
pid = create_child()
if pid == 0:
    while True:  # 子进程死循环打印字符串
        print 'in child process'
        time.sleep(1)
else:
    print 'in father process'
    time.sleep(5)  # 父进程休眠5s再杀死子进程
    os.kill(pid, signal.SIGTERM)
    ret = os.waitpid(pid, 0)  # 收割子进程
    print ret  # 看看到底返回了什么
    time.sleep(5)  # 父进程继续休眠5s观察子进程是否还存在

运行python kill.py输出如下

in father process
in child process
in child process
in child process
in child process
in child process
in child process
(125, 9)

我们看到waitpid返回了一个tuple,第一个是子进程的pid,第二个9是什么含义呢,它在不同的操作系统上含义不尽相同,不过在Unix上,它通常的value是一个16位的整数值,前8位表示进程的退出状态,后8位表示导致进程退出的信号的整数值。所以本例中退出状态位0,信号编号位9,还记得kill -9这个命令么,就是这个9表示暴力杀死进程。

如果我们将os.kill换一个信号才看结果,比如换成os.kill(pid, signal.SIGTERM),可以看到返回结果变成了(138, 15),15就是SIGTERM信号的整数值。

waitpid(pid, 0)还可以起到等待子进程结束的功能,如果子进程不结束,那么该调用会一直卡住。

捕获信号

SIGTERM信号默认处理动作就是退出进程,其实我们还可以设置SIGTERM信号的处理函数,使得它不退出。

# coding: utf-8
import os
import time
import signal
def create_child():
    pid = os.fork()
    if pid > 0:
        return pid
    elif pid == 0:
        return 0
    else:
        raise
pid = create_child()
if pid == 0:
    signal.signal(signal.SIGTERM, signal.SIG_IGN)
    while True:  # 子进程死循环打印字符串
        print 'in child process'
        time.sleep(1)
else:
    print 'in father process'
    time.sleep(5)  # 父进程休眠5s再杀死子进程
    os.kill(pid, signal.SIGTERM)  # 发一个SIGTERM信号
    time.sleep(5)  # 父进程继续休眠5s观察子进程是否还存在
    os.kill(pid, signal.SIGKILL)  # 发一个SIGKILL信号
    time.sleep(5)  # 父进程继续休眠5s观察子进程是否还存在

我们在子进程里设置了信号处理函数,SIG_IGN表示忽略信号。我们发现第一次调用os.kill之后,子进程会继续输出。说明子进程没有被杀死。第二次os.kill之后,子进程终于停止了输出。

接下来我们换一个自定义信号处理函数,子进程收到SIGTERM之后,打印一句话再退出。

# coding: utf-8
import os
import sys
import time
import signal
def create_child():
    pid = os.fork()
    if pid > 0:
        return pid
    elif pid == 0:
        return 0
    else:
        raise
def i_will_die(sig_num, frame):  # 自定义信号处理函数
    print "child will die"
    sys.exit(0)
pid = create_child()
if pid == 0:
    signal.signal(signal.SIGTERM, i_will_die)
    while True:  # 子进程死循环打印字符串
        print 'in child process'
        time.sleep(1)
else:
    print 'in father process'
    time.sleep(5)  # 父进程休眠5s再杀死子进程
    os.kill(pid, signal.SIGTERM)
    time.sleep(5)  # 父进程继续休眠5s观察子进程是否还存在

输出如下

in father process
in child process
in child process
in child process
in child process
in child process
child will die

信号处理函数有两个参数,第一个sig_num表示被捕获信号的整数值,第二个frame不太好理解,一般也很少用。它表示被信号打断时,Python的运行的栈帧对象信息。读者可以不必深度理解。

多进程并行计算实例

下面我们使用多进程进行一个计算圆周率PI。对于圆周率PI有一个数学极限公式,我们将使用该公司来计算圆周率PI。

640?wx_fmt=png

先使用单进程版本

import math
def pi(n):
    s = 0.0
    for i in range(n):
        s += 1.0/(2*i+1)/(2*i+1)
    return math.sqrt(8 * s)
print pi(10000000)

输出

3.14159262176

这个程序跑了有一小会才出结果,不过这个值已经非常接近圆周率了。

接下来我们用多进程版本,我们用redis进行进程间通信。

# coding: utf-8
import os
import sys
import math
import redis
def slice(mink, maxk):
    s = 0.0
    for k in range(mink, maxk):
        s += 1.0/(2*k+1)/(2*k+1)
    return s
def pi(n):
    pids = []
    unit = n / 10
    client = redis.StrictRedis()
    client.delete("result")  # 保证结果集是干净的
    del client  # 关闭连接
    for i in range(10):  # 分10个子进程
        mink = unit * i
        maxk = mink + unit
        pid = os.fork()
        if pid > 0:
            pids.append(pid)
        else:
            s = slice(mink, maxk)  # 子进程开始计算
            client = redis.StrictRedis()
            client.rpush("result", str(s))  # 传递子进程结果
            sys.exit(0)  # 子进程结束
    for pid in pids:
        os.waitpid(pid, 0)  # 等待子进程结束
    sum = 0
    client = redis.StrictRedis()
    for s in client.lrange("result", 0, -1):
        sum += float(s)  # 收集子进程计算结果
    return math.sqrt(sum * 8)
print pi(10000000)

我们将级数之和的计算拆分成10个子进程计算,每个子进程负责1/10的计算量,并将计算的中间结果扔到redis的队列中,然后父进程等待所有子进程结束,再将队列中的数据全部汇总起来计算最终结果。

输出如下

3.14159262176

这个结果和单进程结果一致,但是花费的时间要缩短了不少。

这里我们之所以使用redis作为进程间通信方式,是因为进程间通信是一个比较复杂的技术,我们需要单独一篇文章来仔细讲,各位读者请耐心听我下回分解,我们将会使用进程间通信技术来替换掉这里的redis。

640?wx_fmt=jpeg

阅读python相关高级文章,请关注公众号「码洞」

Python 多进程编程基础与实例 模块是Python标准库中用于多进程编程的模块。它提供了一个类似于threading模块的API,但是能够创建并管理进程,而不是线程。使用模块可以方便地创建子进程,并通过进程间通信(IPC)机制在进程之间传递数据。模块还提供了丰富的工具和函数,用于控制进程的行为,如进程池、锁、事件等。 阅读详情

相关推荐

Python多进程与多线程编程【python基础篇】

Python多进程与多线程编程摘要: Python提供了多进程和多线程两种并发编程方式。多线程通过threading模块实现,线程共享进程内存但需注意线程安全问题。创建线程有两种方式:直接使用Thread类或继承Thread类。线程状态包括新建、就绪、运行、阻塞和终止。为解决线程安全问题,Python提供了锁(Lock)、RLock、Semaphore等同步机制。多进程适用于CPU密集型任务,每个进程有独立内存空间;多线程适用于I/O密集型任务,线程间通信更高效但需处理同步问题。选择哪种方式取决于具体应用场

博客 1793

python多进程

python多进程

weixin_43717602的博客 998

Gitlab+Jenkins+Docker+Harbor+K8s+Rancher集群搭建CICD平台

本文以诺依项目为例详细记录了Kubernetes集群的部署过程以及配套DevOps环境的搭建。主要内容包括:1) 配置8个节点的软硬件环境;2) 基础环境准备(网络、防火墙、Docker等);3) 三节点Kubernetes集群部署;4) GitLab代码仓库安装;5) Harbor私有镜像仓库搭建;6) Jenkins持续集成工具配置;7) 基于若依项目的CI/CD实践;8) Rancher集群管理工具部署。

hickman2023的博客 1206

杀死僵尸进程(defunct)

在Linux中,有时候PS查看进程发现一些进程用kill -9无法杀死,形成了defunct, 即僵尸进程。 这多数情况都是由于父子进程间通信由于某些不知名原因被中途破坏,所以关键核心在于要杀死父进程才行,光kill子进程并不起任何作用。 怎么做? 看看这些进程的ID及其父进程ID: $ ps -ef | grep defunct 显示如下 username 5432 6789 0 17:08 pts/18 00:00:00 grep --color=auto defunct user

flyinmo的博客 4461

MOOS-ivp 实验三 MOOS简介(3)

MOOS-ivp 实验三 MOOS简介(3) 继上一篇文章继续对实验进行记录 提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录MOOS-ivp 实验三 MOOS简介(3)六、A Simple Example with pXRelay1.pXRelay基本使用2.pXRelay简单例子3.pXRelay实验七、First Experiments in Modifying MOOS App Code1.下载一个MOOS模板文件2.打开MOOS模板文件总结 六、A Simple E

weixin_44151170的博客 2535

madgwick算法基于MPU9250姿态融合漂移问题的原因

基于MPU9250的madgwick算法姿态漂移问题原因 0、声明 因为这个是现象是不是共性目前本人还没研究过,只是在个体问题研究的基础上得出的结论,或许我买到的MPU9250是一个盗版:),所以只具备参考性。 1、现象 使用MPU9250的加速度计、角速度计、磁力计(AK8963)原始数据输入到madgwick算法中,得到的姿态最终会在停止姿态变化后仍然漂移一小段时间。其中加速度计和角速度计读取速率为400hz,磁力计为100hz,加速度计采样范围±2g,角速度计采样范...

GreedyZombie的博客 3874

关于Python3多进程机制的一些探索

本文探索了flask中利用多进程实现异步请求的方式

芳樽里的歌的博客 1744

Dataworks实现接口调用

在本地linux虚拟机(不用在意linux版本),安装Anaconda后配置对应的虚拟环境,将虚拟环境的python包整体打包(路径一般为:~/anaconda/envs/env_name/lib/pyyhon3.7/site-packages):上传资源,将第三方包上传至dataworks(注意:所有上传文件均要打包上传,直接上传文件会乱码导致无法使用):PyODPS,其中PyODSP2的python版本为2.7,PyODSP3的python版本为3.7。:在PyODPS中引用资源,然后开发接口。

hutc_Alan的博客 1681

python程序主动退出进程的方式:五种方式总有一种适合你

如果你的程序中包含有线程,用这种方式绝对没错!sys.exit()是一种常用的退出当前进程的方法,它可以终止一个程序的运行,并可以返回一个状态码。当sys.exit()被调用时,程序将立即停止执行,所有的finally子句(如果有的话)将被忽略,并且返回一个标识状态的整数。os._exit()是一种基于系统调用的退出方式,它可以忽略所有的清理活动,包括所有的缓存和终止信号处理器等。当使用os.exit()方法退出时,Python解释器将立即终止程序的运行,不会执行任何清理操作并且不会返回状态码。

3万+

C# 与欧姆龙 PLC 实战:通过 Ethernet/IP 协议进行设备控制与监控

本文介绍了如何通过C#和Ethernet/IP协议实现与欧姆龙PLC的通信。Ethernet/IP是基于以太网的工业协议,适用于工业设备间的实时数据交换。文章详细讲解了使用EthernetIPSharp库建立连接、读写数据的步骤,并提供了示例代码。此外,还探讨了实时监控、报警系统等高级功能,为工业自动化控制系统开发提供了实用指导。该方法简化了PLC通信开发,提高了系统可靠性和智能化程度。

这里只有干货:从 Modbus 通信到 MES 对接,从 YOLO 训练到工控机部署,带你搞定工业软件开发全流程。 816

基于STM32、HAL库的IP5356M_DBZ_CA快充协议芯片简介及驱动程序设计

IP5356M_BATTERY_LEVEL_25 = 1, /* 电池电量25% */IP5356M_CHARGE_STATE_CHARGE_DONE = 4, /* 充电完成 */IP5356M_CHARGE_STATE_FAST = 2, /* 快速充电 */IP5356M_CHARGE_STATE_NONE = 0, /* 无充电 */IP5356M_CHARGE_STATE_PRE = 1, /* 预充电 *//* 延时1秒 */

corlin6688的博客 1419

孤儿进程/僵尸进程<defunct> Z+

1、孤儿进程 爹生孩子;爹死了,孩子还或者,孩子叫孤儿进程;孤儿进程被init进程领养,init进程变为孤儿进程的父亲 int main(){ pid_t pid=fork(); ...

JaweG 867

Prompt进阶2:LangGPT(构建高性能Prompt策略和技巧)--最佳实践指南

Prompt进阶2:LangGPT(构建高性能Prompt策略和技巧)--最佳实践指南

丨汀、的博客 2651

Python多进程编程全指南:从基础到实战

在 Python 开发中,充分利用多核 CPU 资源是提升程序性能的关键。当面对 CPU 密集型任务时,多线程由于 GIL(全局解释器锁)的限制难以发挥多核优势,而多进程编程成为解决这一问题的理想方案。本文将全面介绍 Python 标准库multiprocessing的使用方法,从基础概念到高级技巧,助你轻松掌握多进程编程。

weixin_48552411的博客 1160

51智能小车(双轮)

前几天接了个小单子,是一个基于51单品机的作品,发现自己对小车的认识还是不太🆗。也算是完成了任了的;欢迎各位小伙伴来多多交流,大家一起进步。最后有需要单片机课程设计的小伙伴滴滴我哦(有偿)。企鹅:2397746994。

qq_56992543的博客 2348

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

《100天精通Python——基础篇 2025 第24天:Python 多进程编程入门与实战详解》

本文聚焦 Python 多进程编程,系统讲解 multiprocessing 模块的核心用法,包括 Process 类的使用、进程间通信(队列、管道)、进程池以及进程同步机制。通过实战案例对比多线程与多进程在 CPU 密集型任务中的性能差异,深入理解为何多进程可以突破 GIL 限制,实现真正的并行计算。文章内容循序渐进,帮助读者构建对多进程编程的整体认知,为高性能程序开发打下坚实基础。

XAMO Lab|代码、调试与复盘笔记 1343

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

深入Python多进程编程基础——图文版

多进程编程知识是Python程序员进阶高级的必备知识点,我们平时习惯了使用multiprocessing库来操纵多进程,但是并不知道它的具体实现原理。下面我对多进程的常用...

shellquery的博客 135

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

深入理解Python多进程编程:从基础到实战案例解析

深入理解Python多进程编程:从基础到实战案例解析

学习成长日记 1162

【python内功修炼001】:python多进程编程基础

文章目录一、什么是进程?1、程序的定义:完成特定任务的一系列指令集合2、进程的定义:就是一个运行的程序或者软件。3、进程和程序的区别4、进程的作用二、什么是线程?1、线程的定义:是进程的一个实体三、线程和进程的区别四、浅析并发和并行五、多道程序技术五、浅析同步\异步\阻塞\非阻塞1、同步和异步2、阻塞和非阻塞六、Python进程详解1、进程的创建2、进程的终止3、进程的层次结构4、进程的状态4.1...

金鞍少年的博客 826

Python多进程编程 ---- 基础篇6. Pipe

----------基础篇 引子 创建管道方法: Pipe([duplex]):在进程之间创建一条管道,并返回元组(conn1,conn2),其中conn1,conn2表示管道两端的连接对象,强调一点:必须在产生Process对象之前产生管道。dumplex:默认管道是全双工的,如果将duplex射成False,conn1只能用于接收,conn2只能用于发送。 conn1.recv():接收conn2.send(obj)发送的对象。如果没有消息可接收,recv方法会一直阻塞。如果连接的另外一端已经关闭,那么

愿时光能缓故人不散 563

python基础知识学习——多进程编程

多进程编程1.什么是进程2.进程的层次结构3.进程并发的现象4.multiprocessing模块介绍5.multiprocessing模块的使用开启进程的两种方式互斥锁确定当前进程守护进程终止进程进程通信Queue队列传递Pipe管道通信Managers数据共享 1.什么是进程 进程是系统中正在运行的一个程序,程序一旦运行就是进程。 进程可以看成程序执行的一个实例。进程是系统资源分配的独立实体...

Dim_Jerry的博客 667

python编程图文_深入Python多进程编程基础——图文版

多进程编程知识是Python程序员进阶高级的必备知识点,我们平时习惯了使用multiprocessing库来操纵多进程,但是并不知道它的具体实现原理。下面我对多进程的常用知识点都简单列了一遍,使用原生的多进程方法调用,帮助读者理解多进程的实现机制。代码跑在linux环境下。没有linux条件的,可以使用docker或者虚拟机运行进行体验。docker pull python:2.7生成子进程Pyt...

weixin_40004081的博客 163

深入探究Python多进程编程:Multiprocessing模块基础与实战

在Python编程中,多进程处理是一项关键的技术,特别是在需要处理大规模数据或执行耗时任务时。为了充分利用多核处理器的优势,Python提供了`multiprocessing`模块,使得并行编程变得更加容易。本文将深入探讨`multiprocessing`模块的基础知识,并通过实际代码示例演示其在解决实际问题中的应用。

一键难忘的博客 4297
上一篇: 中国人自己的RPC—— 蚂蚁金服RPC框架结构分析
下一篇: 深入Python多进程编程基础——图文版
码洞
博客等级 码龄10年 41粉丝 137原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值