多任务编程-进程-线程

多任务编程

 一:  进程

 二:  多进程

 三:  线程

 四:  多线程

 五:  其他问题

 

  意义 : 充分利用计算机的资源提高程序的运行效率

  定义 : 通过应用程序利用计算机的多个核心达到同时执行多个任务的目的,一次提高计算机运行效率。

  实施方案 : 多进程 多线程

  并行 : 多个计算机核心在同时处理多个任务,这时多个任务间是并行关系。

  并发 : 同时处理多个任务,内核在多个任务间不断的切换,达到好像都在处理运行的效果。但实际一个时间点内核只能处理其中一个任务。

进程

定义 : 程序在计算机中的一次运行过程

程序 : 是一个可执行的文件,是静态的占有磁盘空间,不占有计算机的运行资源

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

    * 同一个程序的不同运行过程是不同的进程,占用资源和生命周期都不一样。

进程的创建流程
  1.用户空间通过运行程序或者调用接口发起创建进程
  2.操作系统接受用户请求,开始创建进程
  3.操作系统分配计算机资源,确定进程状态,开辟进程空间等工作
  4.操作系统将创建好的进程提供给应用程序使用

cpu时间片

    如果一个进程占有计算机核心,我们称为改进程占有计算机cpu时间片。

    * 多个任务之间是争夺cpu的关系
    * 谁占有cpu最终是操作系统决定

PCB (进程控制块)
    在内存中开辟的一块空间,用来记录进程的信息

    * 进程控制块是操作系统查找识别进程的标志


进程信息 : ps -aux

    PID(process ID) : 在操作系统中每个进程都有一个唯一的ID号用来区别于其他进程。ID号由操作系统自动分配,是一个大于0的整数

父子进程 : 在系统中除了初始化进程,每一个进程都有一个父进程,可能有0个或者多个子进程。由此形成父子进程关系。


查看进程树 : pstree
查看父进程PID: ps -ajx

进程的状态

    三态
        * 就绪态 : 进程具备执行条件,等待系统分配资源
        * 运行态 : 进程占有cpu处于运行状态
        * 等待态 : 进程暂时不具备执行条件,阻塞等待满 足条件后再执行

    五态 (三态基础上增加新建态,终止态)
        * 新建态 : 创建一个新的进程,获取资源的过程
        * 终止态 : 进程执行结束,资源释放回收的过程


ps -aux ---> STAT

    S 等待态 (可中断等待)
    D 等待态 (不可中断等待)
    T 等待态 (暂停状态)
    R 运行态 (包含就绪态)
    Z 僵尸进程

< 高优先级进程
N 优先级较低
l 有子进程的
s 会话组组长
+ 前台进程

进程优先级
    作用 : 决定了一个进程的执行权限和占有资源的优先程度

查看进程优先级 
    top 动态查看系统中的进程信息, 用<>翻页 
    取值范围 -20 -- 19 -20优先级最高

使用指定的优先级运行程序
    nice : 指定运行的优先级
    e.g. nice -9 ./while.py 以优先级9运行
    nice --9 ./while.py 以-9优先级运行    
linux系统下的进程相关操作和其他知识普及

 

进程特征
  1. 进程之间运行互不影响 各自独立运行
  2. 进程是操作系统资源分配的最小单位
  3. 每个进程空间独立,各自占有一定的虚拟内存

------------------------------------------------------------------------------

多任务编程

import os

pid = os.fork()  (注意:在Windows上没有该模块)
  功能 : 创建新的进程
  参数 : 无
  返回值: 失败返回一个负数
  成功 : 在原有进程中返回新的进程的PID号
       在新的进程中返回0

# -*- coding: utf-8 -*-
import os
from time import sleep

print("*******************")
a = 1

pid = os.fork()

if pid < 0:
    print("创建进程失败")
elif pid == 0:
    print("这是新的进程")
    print("a = ", a)
    a = 10000
else:
    sleep(1)
    print("这是原有进程")
    print("parent a =", a)

print("演示完毕")
简单的进程演示
  * 子进程会复制父进程全部代码段,包括fork之前产生的内存空间
  * 子进程从fork的下一句开始执行,与父进程互不干扰
  * 父子进程的执行顺序是不一定的,父子进程公用一个终端显示
  * 父子进程通常会根据fork返回值得差异选择执行不同的代码。所以if结构几乎是fork的固定搭配
  * 父子进程空间独立,操作的都是本空间的内容,互不影响
  * 子进程也有自己的特性,比如PID号,PCB,命令集等

 

进程相关函数

#获取进程PID
os.getpid()
  功能 : 获取当前进程的进程号
  返回值 : 返回进程号

os.getppid()
  功能 : 获取当前进程父进程的PID号
  返回值 : 返回进程号

  进程退出

os._exit(status)
  功能 : 进程退出
  参数 : 进程的退出状态

sys.exit([status])
  功能 : 进程退出
  参数 : 数字表示退出状态,不写默认为0
  字符串,表示退出时打印的内容

  * sys.exit 可以通过捕获 SystemExit异常阻止退出

import os
from time import sleep 

pid = os.fork()

if pid < 0:
    print("Create process failed")
elif pid == 0:
    sleep(1)
    #获取当前进程的PID
    print("Child get pid:",os.getpid())
    #获取父进程的PID
    print("Child get parent pid:",os.getppid())
else:
    print("parent get child pid:",pid)
    print("parent get pid:",os.getpid())
获取PID的演示
孤儿进程: 父进程先于子进程退出,此时子进程就称为孤儿进程。

* 孤儿进程会被操作系统指定的进程收养,系统进程就成为孤儿进程的新的父进程

僵尸进程: 子进程先于父进程退出,但是父进程没有处理子进程的退出状态,此时子进程就会成为僵尸进程。

* 僵尸进程会存留少量PCB信息在内存中,大量的僵尸进程会消耗系统资源,应该避免僵尸进程产生
如何避免僵尸进程产生
    * 处理子进程退出状态
    pid,status = os.wait()
    功能 :在父进程中阻塞等待处理子进程退出
        返回值: pid 退出的子进程的PID号
             status  获取子进程退出状态
        
    pid,status = os.waitpid(pid,option)
    功能 :在父进程中阻塞等待处理子进程退出
    参数 : pid  -1 表示等待任意子进程退出
                 >0 表示等待对应PID号的子进程退出
        option  0 表示阻塞等待
                WNOHANG 表示非阻塞
        返回值: pid 退出的子进程的PID号
             status  获取子进程退出状态
    
    waitpid(-1,0)  ===> wait()

* 让父进程先退出
       1. 父进程创建子进程等待子进程退出
       2. 子进程创建二级子进程后立即退出
       3. 二级子进程称为孤儿,和原来的父进程各自执行    事件
孤儿进程和僵尸进程,以及如何避免僵尸进程的发生 

-------------------------------------------------------------------------

多任务编程

multiprocessing 模块创建进程

1. 需要将要执行的事情封装为函数
2. 使用multiprocessing模块中Process类创建进程对象
3. 通过对象属性设置和Process的初始化函数对进程进行设置,绑定要执行的函数
4. 启动进程,会自动执行进程绑定的函数
5. 完成进程的回收


Process()   注意:在windows中Process()必须放到# if __name__ == '__main__':下

由于Windows没有fork,多处理模块启动一个新的Python进程并导入调用模块。 
如果在导入时调用Process(),那么这将启动无限继承的新进程(或直到机器耗尽资源)。 
这是隐藏对Process()内部调用的原,使用if __name__ == “__main __”,这个if语句中的语句将不会在导入时被调用。

  功能 : 创建进程对象
  参数 : name 进程名称 Process-1
  target 绑定函数
  args 元组 给target函数按照位置传参
  kwargs 字典 给target函数按照键值对传参

p.start()
  功能:启动进程
  * target函数会自动执行,此时进程真正被创建

p.join([timeout])
  功能 : 阻塞等待回收子进程
  参数 : 超时时间

  * 使用multiprocessing创建子进程,同样子进程复制父进程的全部代码段,父子进程各自执行互不影响,父子进程有各自的运行空间

  * 如果不使用join回收子进程则子进程退出后会成为僵尸进程
  * 使用multiprocessing创建子进程往往父进程只是用来创建进程回收进程

 

# -*- coding: utf-8 -*-
from multiprocessing import Process
from time import sleep

def p1():
    print('Hello!')

if __name__ == '__main__':
    p = Process(target=p1)
    p.start()

    sleep(2)
    print('这是父进程!')

    p.join()
注意
    1. 如果子进程从父进程拷贝对象,对象和网络或者文件相关联,那么父子进程会使用同一套对象属性,相互有一定的关联性
    2. 如果在子进程中单独创建对象,则和父进程完全没有关联

 

Process进程对象属性

  p.start()
  p.join()

  p.is_alive()
    判断进程生命周期状态,处于生命周期得到True否则返回False

  p.name 进程名称 默认为Process-1
  p.pid 进程的PID号

  p.daemon
    默认状态False 主进程退出不会影响子进程执行
    如果设置为True 则子进程会随着主进程结束而结束

  * 要在start前设置
  * 一般不和join一起使用


创建自定义进程类

  1. 继承Process
  2. 编写自己的__init__ ,同时加载父类init方法
  3. 重写run方法,可以通过生成的对象调用start自动运行

 

多进程

线程

 

多线程

其他问题

posted on 2018-11-01 11:20  蓝天梦nice  阅读(258)  评论(0)    收藏  举报

导航