python并发编程基础

一、多任务编程

  1. 意义: 充分利用计算机多核资源,提高程序的运行效率。

  2. 实现方案 :多进程 , 多线程

  3. 并行与并发

    并发 : 同时处理多个任务,内核在任务间不断的切换达到好像多个任务被同时执行的效果,实际每个时刻只有一个任务占有内核。

    并行 : 多个任务利用计算机多核资源在同时执行,此时多个任务间为并行关系。

二、进程(process)

  进程理论基础

    1. 定义 : 程序在计算机中的一次运行。

      1> 程序是一个可执行的文件,是静态的占有磁盘。

      2> 进程是一个动态的过程描述,占有计算机运行资源,有一定的生命周期。

    2. 系统中如何产生一个进程

      【1】 用户空间通过调用程序接口或者命令发起请求

      【2】 操作系统接收用户请求,开始创建进程

      【3】 操作系统调配计算机资源,确定进程状态等

      【4】 操作系统将创建的进程提供给用户使用

        

    3.进程基本概念

      cpu时间片:如果一个进程占有cpu内核则称这个进程在cpu时间片上。

      PCB(进程控制块):在内存中开辟的一块空间,用于存放进程的基本信息,也用于系统查找识别进程。

      进程ID(PID): 系统为每个进程分配的一个大于0的整数,作为进程ID。每个进程ID不重复。

      Linux查看进程ID : ps -aux

      父子进程 : 系统中每一个进程(除了系统初始化进程)都有唯一的父进程,可以有0个或多个子进程。父子进程关系便于进程管理。

      查看进程树: pstree

      进程状态

        三态

          就绪态 : 进程具备执行条件,等待分配cpu资源

          运行态 : 进程占有cpu时间片正在运行

          等待态 : 进程暂时停止运行,让出cpu

        

        五态 (在三态基础上增加新建和终止)

          新建 : 创建一个进程,获取资源的过程

          终止 : 进程结束,释放资源的过程

          

        状态查看命令 : ps -aux --> STAT列

          S 等待态

          R 执行态

          D 等待态

          T 等待态

          Z 僵尸

          < 有较高优先级

          N 优先级较低

          + 前台进程

          s 会话组组长

          l 有多线程的

        进程的运行特征

          【1】 进程可以使用计算机多核资源

          【2】 进程是计算机分配资源的最小单位

          【3】 进程之间的运行互不影响,各自独立

          【4】 每个进程拥有独立的空间,各自使用自己空间资源

  基于fork的多进程编程

    fork使用

      pid = os.fork()

        功能: 创建新的进程

        返回值:整数,如果创建进程失败返回一个负数,如果成功则在原有进程中返回新进程的PID,在新进程中返回0

      注意

        1>子进程会复制父进程全部内存空间,从fork下一句开始执行。

        2>父子进程各自独立运行,运行顺序不一定。

        3>利用父子进程fork返回值的区别,配合if结构让父子进程执行不同的内容几乎是固定搭配。

        4>父子进程有各自特有特征比如PID PCB 命令集等。

        5>父进程fork之前开辟的空间子进程同样拥有,父子进程对各自空间的操作不会相互影响。

    进程相关函数

      os.getpid()

        功能: 获取一个进程的PID值

        返回值: 返回当前进程的PID

      os.getppid()

        功能: 获取父进程的PID号

        返回值: 返回父进程PID

      os._exit(status)

        功能: 结束一个进程

        参数:进程的终止状态

      sys.exit([status])

        功能:退出进程

        参数:整数 表示退出状态

           字符串 表示退出时打印内容

    孤儿和僵尸        

      1. 孤儿进程 : 父进程先于子进程退出,此时子进程成为孤儿进程。

        特点: 孤儿进程会被系统进程收养,此时系统进程就会成为孤儿进程新的父进程,孤儿进程退出该进程会自动处理。

      2. 僵尸进程 : 子进程先于父进程退出,父进程又没有处理子进程的退出状态,此时子进程就会称为僵尸进程。

        特点: 僵尸进程虽然结束,但是会存留部分PCB在内存中,大量的僵尸进程会浪费系统的内存资源。

      3. 如何避免僵尸进程产生

        1>使用wait函数处理子进程退出

          pid,status = os.wait()

            功能:在父进程中阻塞等待处理子进程退出

            返回值: pid 退出的子进程的PID

            status 子进程退出状态

          pid,status = os.waitpid(pid,option)

            功能: 在父进程中处理子进程退出状态

            参数: pid -1 表示等待任意子进程退出

                 >0 表示等待指定的子进程退出

               option 0 表示阻塞等待

                  WNOHANG 表示非阻塞

            返回值:pid 退出的子进程的PID

                status 子进程退出状态

        2>创建二级子进程处理僵尸

          【1】 父进程创建子进程,等待回收子进程

          【2】 子进程创建二级子进程然后退出

          【3】 二级子进程称为孤儿,和原来父进程一同执行事件

        3>通过信号处理子进程退出

          原理: 子进程退出时会发送信号给父进程,如果父进程忽略子进程信号,则系统就会自动处理子进程退出。

          方法: 使用signal模块在父进程创建子进程前写如下语句 :

            import signal

            signal.signal(signal.SIGCHLD,signal.SIG_IGN)

          特点 : 非阻塞,不会影响父进程运行。可以处理所有子进程退出

  multiprocessing 模块创建进程

    进程创建方法

      1. 流程特点

        【1】 将需要子进程执行的事件封装为函数

        【2】 通过模块的Process类创建进程对象,关联函数

        【3】 可以通过进程对象设置进程信息及属性

        【4】 通过进程对象调用start启动进程

        【5】 通过进程对象调用join回收进程

      2. 基本接口使用

        Process()

          功能 : 创建进程对象

          参数 :  target 绑定要执行的目标函数

              args 元组,用于给target函数位置传参

              kwargs 字典,给target函数键值传参

        p.start()

          功能 : 启动进程

        注意:启动进程此时target绑定函数开始执行,该函数作为子进程执行内容,此时进程真正被创建

        p.join([timeout])

          功能:阻塞等待回收进程

          参数:超时时间

        注意:

          1>使用multiprocessing创建进程同样是子进程复制父进程空间代码段,父子进程运行互不影响。

          2>子进程只运行target绑定的函数部分,其余内容均是父进程执行内容。

          3>multiprocessing中父进程往往只用来创建子进程回收子进程,具体事件由子进程完成。

          4>multiprocessing创建的子进程中无法使用标准输入

      3. 进程对象属性

        p.name 进程名称

        p.pid 对应子进程的PID号

        p.is_alive() 查看子进程是否在生命周期

        p.daemon 设置父子进程的退出关系

          1>如果设置为True则子进程会随父进程的退出而结束

          2>要求必须在start()前设置

          3>如果daemon设置成True 通常就不会使用 join()

    进程池实现

      1. 必要性

        【1】 进程的创建和销毁过程消耗的资源较多

        【2】 当任务量众多,每个任务在很短时间内完成时,需要频繁的创建和销毁进程。此时对计算机压力较大

        【3】 进程池技术很好的解决了以上问题。

      2. 原理

        创建一定数量的进程来处理事件,事件处理完进 程不退出而是继续处理其他事件,直到所有事件全都处理完毕统一销毁。增加进程的重复利用,降低资源消耗。

      3. 进程池实现

        【1】 创建进程池对象,放入适当的进程

            from multiprocessing import Pool

            Pool(processes)

              功能: 创建进程池对象

              参数: 指定进程数量,默认根据系统自动判定

        【2】 将事件加入进程池队列执行

            pool.apply_async(func,args,kwds)

            功能: 使用进程池执行 func事件

            参数: func 事件函数

               args 元组 给func按位置传参

               kwds 字典 给func按照键值传参

            返回值: 返回函数事件对象

        【3】 关闭进程池

            pool.close()

              功能: 关闭进程池

        【4】 回收进程池中进程

            pool.join()

              功能: 回收进程池中进程

    进程间通信(IPC)

      1. 必要性: 进程间空间独立,资源不共享,此时在需要进程间数据传输时就需要特定的手段进行数据通信。

      2. 常用进程间通信方法

        管道 消息队列 共享内存 信号 信号量 套接字

        1>管道通信(Pipe)

          1. 通信原理:在内存中开辟管道空间,生成管道操作对象,多个进程使用同一个管道对象进行读写即可实现通信

          2. 实现方法

            from multiprocessing import Pipe

            fd1,fd2 = Pipe(duplex = True)

            功能: 创建管道

            参数:默认表示双向管道

               如果为False 表示单向管道

            返回值:表示管道两端的读写对象

                如果是双向管道均可读写

                如果是单向管道fd1只读 fd2只写

            

            fd.recv()

            功能 : 从管道获取内容

            返回值:获取到的数据

            fd.send(data)

            功能: 向管道写入内容

            参数: 要写入的数据

        2>消息队列

          1.通信原理:在内存中建立队列模型,进程通过队列将消息存入,或者从队列取出完成进程间通信。

          2. 实现方法

            from multiprocessing import Queue

            q = Queue(maxsize=0)

            功能: 创建队列对象

            参数:最多存放消息个数

            返回值:队列对象

            q.put(data,[block,timeout])

            功能:向队列存入消息

            参数:data 要存入的内容

               block 设置是否阻塞 False为非阻塞

               timeout 超时检测

            q.get([block,timeout])

            功能:从队列取出消息

            参数:block 设置是否阻塞 False为非阻塞

               timeout 超时检测

            返回值: 返回获取到的内容

            q.full() 判断队列是否为满

            q.empty() 判断队列是否为空

            q.qsize() 获取队列中消息个数

            q.close() 关闭队列

        3>共享内存

          1. 通信原理:在内中开辟一块空间,进程可以写入内容和读取内容完成通信,但是每次写入内容会覆盖之前内容。

          2. 实现方法

            

            from multiprocessing import Value,Array

            obj = Value(ctype,data)

            功能 : 开辟共享内存

            参数 : ctype 表示共享内存空间类型 ‘i‘ ‘f‘ ‘c‘

            data 共享内存空间初始数据

            返回值:共享内存对象

            obj.value 对该属性的修改查看即对共享内存读写

            obj = Array(ctype,data)

            功能: 开辟共享内存空间

            参数: ctype 表示共享内存数据类型

            data 整数则表示开辟空间的大小,其他数据类型 表示开辟空间存放

            返回值:共享内存对象

            Array共享内存读写: 通过遍历obj可以得到每个值,直接可以通过索引序号修改任意值。

            * 可以使用obj.value直接打印共享内存中的字节串

        4>本地套接字

          1. 功能 : 用于本地两个程序之间进行数据的收发

          2. 套接字文件 :用于本地套接字之间通信时,进行数据传输的介质。

          3. 创建本地套接字流程

            【1】 创建本地套接字

              sockfd = socket(AF_UNIX,SOCK_STREAM)

            【2】 绑定本地套接字文件

              sockfd.bind(file)

            【3】 监听,接收客户端连接,消息收发

              listen()-->accept()-->recv(),send()

        5>信号量(信号灯集)

          1. 通信原理:给定一个数量对多个进程可见。多个进程都可以操作该数量增减,并根据数量值决定自己的行为。

          2. 实现方法

              from multiprocessing import Semaphore

              sem = Semaphore(num)

              功能 : 创建信号量对象

              参数 : 信号量的初始值

              返回值 : 信号量对象

              sem.acquire() 将信号量减1 当信号量为0时阻塞

              sem.release() 将信号量加1

              sem.get_value() 获取信号量数量

三、线程编程(Thread)

  线程基本概念

    1. 什么是线程

      【1】 线程被称为轻量级的进程

      【2】 线程也可以使用计算机多核资源,是多任务编程方式

      【3】 线程是系统分配内核的最小单元

      【4】 线程可以理解为进程的分支任务

    2. 线程特征

      【1】 一个进程中可以包含多个线程

      【2】 线程也是一个运行行为,消耗计算机资源

      【3】 一个进程中的所有线程共享这个进程的资源

      【4】 多个线程之间的运行互不影响各自运行

      【5】 线程的创建和销毁消耗资源远小于进程

      【6】 各个线程也有自己的ID等特征

  threading模块创建线程

    【1】 创建线程对象

      from threading import Thread

      t = Thread()

        功能:创建线程对象

        参数:target 绑定线程函数

           args 元组 给线程函数位置传参

           kwargs 字典 给线程函数键值传参

    【2】 启动线程

      t.start()

    【3】 回收线程

      t.join([timeout])

  线程对象属性

    t.name 线程名称

    t.setName() 设置线程名称

    t.getName() 获取线程名称

    t.is_alive() 查看线程是否在生命周期

    t.daemon 设置主线程和分支线程的退出关系

    t.setDaemon() 设置daemon属性值

    t.isDaemon() 查看daemon属性值

    daemon为True时主线程退出分支线程也退出。要在start前设置,通常不和join一起使用。

  

  自定义线程类

    1. 创建步骤

      【1】 继承Thread类

      【2】 重写__init__方法添加自己的属性,使用super加载父类属性

      【3】 重写run方法

    2. 使用方法

      【1】 实例化对象

      【2】 调用start自动执行run方法

      【3】 调用join回收线程

  

原文地址:https://www.cnblogs.com/yuxiangyang/p/10885385.html

时间: 2024-11-10 13:42:30

python并发编程基础的相关文章

python并发编程基础之守护进程、队列、锁

并发编程2 1.守护进程 什么是守护进程? 表示进程A守护进程B,当被守护进程B结束后,进程A也就结束. from multiprocessing import Process import time ? def task(): print('妃子的一生') time.sleep(15) print('妃子死了') ? if __name__ == '__main__': fz = Process(target=task) fz.daemon = True #将子进程作为主进程的守护进程.必须在

Python并发编程基础 №⑧ 并发完结篇:IO模型

1.详细介绍 为了更好地了解IO模型,我们需要事先回顾下:同步.异步.阻塞.非阻塞 同步(synchronous):就是一个任务的完成需要依赖另外一个任务时,只有等待被依赖的任务完成后,依赖的任务才能算完成,这是一种可靠的任务序列.要么成功都成功,失败都失败,两个任务的状态可以保持一致. 异步(asynchronous):是不需要等待被依赖的任务完成,只是通知被依赖的任务要完成什么工作,依赖的任务也立即执行,只要自己完成了整个任务就算完成了.至于被依赖的任务最终是否真正完成,依赖它的任务无法确定

python中并发编程基础1

并发编程基础概念 1.进程. 什么是进程? 正在运行的程序就是进程.程序只是代码. 什么是多道? 多道技术: 1.空间上的复用(内存).将内存分为几个部分,每个部分放入一个程序,这样同一时间在内存中就有了多道程序. 2.时间上的复用(CPU的分配).只有一个CPU,如果程序在运行过程中遇到了I/O阻塞或者运行时间足够长.操作系统会按照算法将CPU分配给其他程序使用,依次类推.直到第一个程序被重新分配到CPU会继续运行. 多道技术中的问题解决: 空间复用:程序之间的内存必须分割.这种分割需要在硬件

python网络编程基础(线程与进程、并行与并发、同步与异步)

python网络编程基础(线程与进程.并行与并发.同步与异步) 目录 线程与进程 并行与并发 同步与异步 线程与进程 进程 前言 进程的出现是为了更好的利用CPU资源使到并发成为可能. 假设有两个任务A和B,当A遇到IO操作,CPU默默的等待任务A读取完操作再去执行任务B,这样无疑是对CPU资源的极大的浪费.聪明的老大们就在想若在任务A读取数据时,让任务B执行,当任务A读取完数据后,再切换到任务A执行.注意关键字切换,自然是切换,那么这就涉及到了状态的保存,状态的恢复,加上任务A与任务B所需要的

Python并发编程系列之多线程

1引言 2 创建线程 2.1 函数的方式创建线程 2.2 类的方式创建线程 3 Thread类的常用属性和方法 3.1 守护线程:Deamon 3.2 join()方法 4 线程间的同步机制 4.1 互斥锁:Lock 4.2 递归锁:RLock 4.3 Condition 4.4 信号量:Semaphore 4.5 事件:Event 4.6 定时器:Timer 5 线程间的通行 5.1队列:Queue 6 线程池 7 总结 1 引言 上一篇博文详细总结了Python进程的用法,这一篇博文来所以说

进程,操作系统,Python并发编程之多进程

1.进程基础知识 1.程序:若干文件 2.进程:一个正在执行的文件,程序 3.进程被谁执行:cpu最终运行指定的程序 4.操作系统调度作用:将磁盘上的程序加载到内存,然后交由CPU去处理,一个CPU正在运行的一个程序,就叫开启了一个进程 2.操作系统 1.操作系统:存在于硬盘与软件之间,管理.协调.控制软件与硬件的交互 2.操作系统的作用:将一些复杂的硬件封装成简单的借口,便于使用;合理地调度分配多个进程与cpu的关系,让其有序化 3.操作系统发展史 ①第一代电子计算机(1940-1955) 二

python并发编程之多进程

python并发编程之多进程 一.什么是进程 进程:正在进行的一个过程或者一个任务,执行任务的是CPU. 原理:单核加多道技术 二.进程与程序的区别 进程是指程序的运行过程 需要强调的是:同一个程序执行两次是两个进程,比如打开暴风影音,虽然都是同一个软件,但是一个可以播放苍井空,另一个可以播放武藤兰. 三.并发与并行 无论是并行还是并发,在用户看来都是'同时'运行的,不管是进程还是线程,都只是一个任务而已,真是干活的是cpu,cpu来做这些任务,而一个cpu同一时刻只能执行一个任务. (1)并发

python-学习-python并发编程之多进程与多线程

一 multiprocessing模块介绍 python中的多线程无法利用多核优势,如果想要充分地使用多核CPU的资源(os.cpu_count()查看),在python中大部分情况需要使用多进程.Python提供了multiprocessing.    multiprocessing模块用来开启子进程,并在子进程中执行我们定制的任务(比如函数),该模块与多线程模块threading的编程接口类似.  multiprocessing模块的功能众多:支持子进程.通信和共享数据.执行不同形式的同步,

Python并发编程实例教程

有关Python中的并发编程实例,主要是对Threading模块的应用,文中自定义了一个Threading类库. 一.简介 我们将一个正在运行的程序称为进程.每个进程都有它自己的系统状态,包含内存状态.打开文件列表.追踪指令执行情况的程序指针以及一个保存局部变量的调用栈.通常情况下,一个进程依照一个单序列控制流顺序执行,这个控制流被称为该进程的主线程.在任何给定的时刻,一个程序只做一件事情. 一个程序可以通过Python库函数中的os或subprocess模块创建新进程(例如os.fork()或