欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

多任务编程学习笔记

程序员文章站 2022-05-27 09:43:57
...

多任务编程

通过应用程序利多个计算机核心达到多任务同时执行的目的,一次来提升程序的执行效率

多进程,多线程

进程:程序在计算机中一次执行的过程; 

程序和进程的区别:
程序:是一个静态的描述,不占计算机资源
进程:是一个动态的过程,占用CPU内存的资源,有一定的生命周期

同一个程序,每次执行都是不同的进程,因为分配的计算机资源不同

1, 进程的创建流
用户空间运行程序,发起进程创建申请
---> 调用操作系统内核接口创建进程
---> 分配计算机资源,确定进程状态 
---> 将新的进程提供给用户使用

2, 多个进程如何占用CPU
    a, 一个内核同一个时刻只能运行一个任务
    b, 多个进程对内核资源进行争夺,操作系统决定那个进程占有计算资源
    c, 占有计算机的计算资源,我们称为占有cpu的时间片
    
3, 进程有哪些信息如何保存
PCB--Process Control Block: 在linux/unix系统中进程创建后,会在内存开辟一块空间存放进程的相关信息,称为PCB
ps -aux


4, 进程特征
    a, 进程是操作系统 资源分配的最小单位;(线程是占有cpu内核的最小单位)
    b, 每个进程单独占有4G的虚拟内存
    c, 进程之间相互独立,运行不受影响
    
进程的状态:有三态和五态之说
三态:
就绪态:进程具备运行条件,等待系统分配cpu资源
运行态: 进程占用cpu,处于运行的状态
等待态/阻塞:又称为阻塞态,睡眠态,指进程暂时不具备运行的条件,需要阻塞等待(sleep, accept...)

五态
三态+ 新建和终止 两状态


ps -aux --> STAT 表示进程装填
D: 等待态--不可中断等待
S:等待态--可中断等待
T:等待态--暂停Time-out
R:运行态run
Z:僵尸态 


+     前台进程 (不带+,后台进程)
<   高优先级    
N     低优先级    Negative
l    有进程链 link, 有关联进程
s    会话组 session,有一组进程;


进程优先级:
进程优先级决定一个进程的执行权限和占有资源的有线程度
top:动态查看当前运行的进程状态, NI表示优先级, <>翻页

linux中优先级范围
-20 -- 19 
-20最高
用户程序默认优先级0


nice:以指定的优先级运行进程
nice -9  command

renice: 改变进程的优先级
renice 优先级   pid


进程树
pstree


使用两个进程分别完成预定事件

os.fork()
功能: 创建一个新的进程
参数: 无
返回值:
    失败,返回是一个负数 ,一般是 -1
    成功:0    在子进程中fork的返回值
    >0 的正整数,(新的进程PID),在父进程中的返回值
    
如果成功,os.fork() 会在内存中开辟一个新的内存空间,并将代码自我COPY一份到新内存空间,即创建一个新的子进程;
此时父进程os.fork()返回新创建子进程的pid 号, 子进程开辟新空间后也会执行相同代码--从os.fork()执行;
但子进程os.fork()返回值为0; 

注意: 1, 在fork()之前有print(),将值会print1次,子进程只执行fork下面的代码
        2, fork()之前有变量,子进程也会有该变量;因为父进程复制子进程所有代码段
        3, fork()之后的修改不会影响到对方,父子进程执行上互不影响
        4, 子进程虽然复制父进程的空间,但是有自己的特性,比如自己的pid,进程PCB,进程栈空间等;
   

举例说明:

#洗衣服需要10min, 烧水需要6min;
#两间事情需要同时处理
import os
from time import sleep

#创建进程
pid = os.fork()

#创建子进程失败
if pid < 0:
    print("create process failed")

#创建子进程成功,处理子进程
elif pid == 0:
    print("This is childprocess:pid return  {}".format(pid))
    for _ in range(1,7):
        sleep(1)
        print('烧水时间{}'.format(_))
    print('水烧开啦.')

#创建子进程成功,处理父进程部分
else:
    print("父进程执行, this is father process, my childprocess pid= {}".format(pid))
    for _ in range(1,11):
        sleep(1)
        print('洗衣服时间:{}'.format(_))
    print('衣服洗完啦!')

print("finished")

进程相关函数:
os.getpid()     获取当前进程的pid,返回值即PID
os.getppid()    功能:获取当前进程父进程的PID
os._exit(status)功能: 结束一个进程
                参数: 表示进程的结束状态,是一个整数
sys.exit([status])
功能: 结束一个进程,抛出异常,可以被try捕获
参数: 传入一个正整数,表示结束状态; 
        传入一个字符串,表示结束打印

import os
from time import sleep

pid = os.fork()

if pid < 0:
    print('创建失败')
elif pid == 0:
    sleep(0.1)
    print("子进程")
    print(os.getpid())    #获取自己的pid
    print(os.getppid())    #获取父进程pid
    print("--------------------")

else:
    print("父进程")
    print(pid)
    print(os.getpid())


    
    

孤儿进程:父进程先于子进程退出,此时子进程变为孤儿进程; 
        孤儿进程会被系统指定进程所”收养“,该进程称为孤儿继承的新父进程

eg:

import os
from time import sleep

pid = os.fork()

if pid < 0:
	print('childprocess failed')
elif pid == 0:
	print('created childprocess')
    #打印父进程pid
	print('child's old father process pid:', os.getppid())
    #进行sleep,此时父进程已结束,孤儿进程被继父接管;
	sleep(0.1)
	print('new father PID:', os.getppid())
	
else:
	print('father process pid:', os.getpid())

僵尸进程:    子进程先于父进程退出,但父进程没有处理子进程的退出状况,子进程就会称为僵尸进程

*僵尸进程会滞留PCB的部分信息在内存中,大量的僵尸进程会消耗系统资源,所以应尽量避免僵尸进程的产生

eg:创建僵尸进程

import os

pid = os.fork()

if pid < 0:
    print('failed')
elif pid == 0:
    print(os.getpid())
else:
    #子进程完成,父进程未处理;从而成为僵尸进程
    while True:
        pass

如何避免僵尸进程的产生:
    1, 让父进程先退出(不易控制)
    2, 让父进程处理子进程的退出
        *使用wait或者waitpid函数
        *使用信号处理
    3, 创建二级子进程
    
os.wait()
功能: 等待子进程的退出
参数: 无
返回值: 一个二元元祖,第一个值为退出的子进程PID,第二个只为子进程的退出状态


os.waitpid(pid,option)
功能: 处理子进程的退出
参数:pid: -1 表示等待任意子进程的退出
            >0 表示等待相应PID号的子进程退出
     option: 0 表示阻塞等待
            os.WNOHANG: 表示非阻塞等待
返回值: 一个二元元祖,第一个值为退出的子进程PID,第二个只为子进程的退出状态

            
os.waitpid(-1,0) 等效 os.wait()

import os
from time import sleep

pid = os.fork()

if pid < 0:
    print('childprocess failed')
elif pid == 0:
    sleep(5)
    print('created childprocess')
    print('childs old father process pid:', os.getppid())
    sleep(0.1)
    
else:
    #设置为非阻塞状态,循环处理,查看子进程状态
    while True:
        sleep(1)
        p,status = os.waitpid(pid,os.WNOHANG)
        print(p,status)
        print('father process pid:', os.getpid())
    while True:
        pass

创建二级子进程
    父进程创建子进程,处理特定时期;
    子进程创建二级子进程,处理额外的事情
    一级子进程退出,使二级子进程称为孤儿进程,被接管;
    从而父进程和二级子进程相互处理不同事情,互不影响

二级子进程代码

#创建二级子进程处理僵尸进程
import os
from time import sleep

#子进程函数
def subprocess():
	childpid = os.fork()
	if childpid < 0:
		print('二级子进程创建失败')
	elif childpid == 0:
		print('二级子进程创建成功',os.getpid())
		print('做其他事情')
	else:
		os._exit(0)
		
		
pid = os.fork()

if pid < 0:
	print('创建失败')
	os._exit(0)
elif pid == 0:
	#创建二级子进程
    print('创建一级子进程成功')
	subprocess()
else:
	p,status = os.wait()
	print(p,status)
	print('这是父进程, pid', pid)
	print('do something')