进程

操作系统的发展史

老式计算机的手工操作特点:

1.用户独占全机,不会出现因资源已被其它用户占用而等待的现象,但资源利用率低。

2.CPU等待手工操作。CPU的利用不充分。

手工操作属于单道程序,也就是主机内存中只能执行一个程序,其它的程序只能等待它执行完后才能执行。

多道

多道程序设计技术就是指允许多个程序同时进入内存并运行。

 

优点:

1.空间上的复用:

多个程序共用一套计算机硬件

2.时间上的复用(切换+保存状态)

①.当一个程序遇到IO操作,操作系统会剥夺该程序的CPU执行权限(提高了CPU的利用率,并且不影响程序的执行效率)

②.当一个程序长时间占用CPU操作系统也会剥夺该程序的CPU执行权限(降低程序的执行效率)

进程理论

进程和程序

程序:就是一坨代码

进程:就是正在运行的程序

多个进程执行时的进程调度

多个进程交替运行,操作系统必须对这些进程进行调度,这个调度也不是随机进行的,而是需要遵循一定的法则,于是有了进程的调度算法。

1.先来先服务:谁先来就给谁先服务,先来的程序先进行运行。

2.短作业优先调度:谁消耗的时间比较短,先运行谁。

3.时间片轮转法和4.多级反馈队列

同步异步、阻塞非阻塞

同步异步:表示的是程序的运行状态

同步:任务提交之后,原地等待的任务执行并拿到返回结果才走,期间不做任何事情(在代码层面看就是卡住了)

异步:任务提交之后,不再原地等待,而是继续执行下一行代码(通过其它的方式拿到结果)

阻塞和非阻塞:表示的程序的运行状态

阻塞:阻塞态

非阻塞:就绪态,运行态

 

(1)就绪(Ready)状态

  当进程已分配到除了CPU外的所有资源时,只要获得处理机便可以立即执行,这是的进程状态就是就绪态。

 (2)运行(Running)状态

  当进程已获得处理机制,其它程序正在处理机上执行,这时的进程状态被称为就绪态。

(3)阻塞(Blocked)状态

  正在执行的状态,由于等待某个事件发生而无法执行时,便放弃处理机而处于阻塞状态。引起进程阻塞的事件可能有很多种,比如等待I\O才做、申请缓冲区不能满足、等待信号等。

创建进程的两种方式

 multiprocess模块

multiprocess并不是一个模块,而是python中一个操作、管理进程的包。之所以叫mulit是取自multiple的多功能的意思,这个包几乎包含了和进程有关的所有子模块。

multiprocess.process模块

Process模块

process模块是一个创建进程的模块,借助这个模块,就可以完成进程的创建。

#使用process模块创建进程
from multiprocessing import Process
import time

def test(name):
    print('%s is running'%name)
    print('%s is over'%name)

# windows创建进程一定要在if __name__ == '__main__':代码块内创建  否则报错
if __name__ == '__main__':
    p = Process(target=test,args=('egon',))  #创建一个进程对象
    p.start()  # 告诉操作系统帮你创建一个进程
    time.sleep(1)
    print('')

windows创建进程一定要在__main__中写,因为windows会将代码以模块的方式,从上往下执行一遍,而linux会直接将代码完完整整的拷贝一份。

#以继承Process类的形式开启进程的方式
from multiprocessing import Process
import time
class MyProcess(Process):
    def __init__(self,name):
        super().__init__()
        self.name = name

    def run(self):
        print('%s is running'% self.name)
        time.sleep(3)
        print('%s is over'%self.name)

if __name__ =='__main__':
    p = MyProcess('egon')
    p.start()
    print('')

创建进程就是在内存中重新开辟一块内存空间,将允许产生的代码丢进去,一个进程对应在内存里的就是一块独立的内存空间。

#进程间的数据是隔离的
from multiprocessing import Process
import time

money = 100

def test():
    global money  #  修改全局变量,通过这个来进行测试
    money = 99999

if __name__ == '__main__':
    p = Process(target = test)
    p.start()
    p.join()
    print(money)

>>>:100
#创建的子进程和主进程是两个独立的空间,代码块是在子进程中执行的,所以只能修改子进程空间中的变量,主进程空间不受到影响

进程对象以及一些方法

join方法

def f(name):
    print('hello',name)
    time.sleep(1)
    print('子进程在此')

if __name__ == '__main__':
    p = Process(target=f,args=('bob',))
    p.start()  
    p.join()
    print('父进程在此')

#start()它起到的作用的作用是让操作系统帮你创建一个进程,至于什么时候创建,由操作系统随机决定
#当我们想让子进程先运行的时候我们可以用join,它的作用是让主进程等待子进程的运行结束

terminate和is_alive

from multiprocessing import Process,current_process
import os
import time

def test(name):
    print('%s is running'%name,'子进程%s'%s.getpid(),'父进程%s'%os.getppid)
    time.sleep(3)
    print('%s is over'%name)

if __name__ == '__main__':
    p = Process(targs=test,args=('egon',))
    p.start()
    p .termainate()  # 杀死当前进程
    time.sleep(0.1)
    print(p.si_alive)
    time.sleep(0.1)
    print(p.is_alive)  # 判断是否存活
    print('',os.getpid(),'主主进程%s'%os.getppid())

守护进程

from multiprocessing import Process
import time

def test(name):
    print('%s总管正常活着'%name)
    time.sleep(1)
    print('%s总管正常死亡'%name)

if __name__ == '__main__':
    p = Process(target=test,args=('egon',))
    #p.daemon = True  # 守护进程,当主程序代码运行结束之后,守护进程随机终止
    p.start()
    time.sleep(0.1)
    print('皇帝jason寿终正寝')

僵尸进程和孤儿进程

僵尸进程:当进程结束之后还保留着一些信息以及它占用的PID,所有的进程都步入成僵尸进程。

  父进程回收子进程资源的两种方式

    1.join方法

    2.父进程正常死亡

孤儿进程:子进程没死,但父进程意外死亡

     针对linux会有儿童福利院(init)如果父进程意外死亡他创建的子进程都会被福利院收养

互斥锁

多个程序操作用一份数据的时候会出现数据错乱的现象。

避免的方法:将操作数据的部分加锁处理,会将并发变成串行牺牲了效率但是保证了数据的安全。

#写一个简单的抢票系统
from multiprocessing import Process,Lock
import time
import json

#查询余票
def search(i):
    with open('data','r',encoding='utf-8') as f:
        data = f.read()
    t_d = json.loads(data)
    print('用户%s查询余票为:%s'%(i,t_d.get('ticket')))

#买票
def buy(i):
    with open('data','r',encoding='utf-8') as f:
        data = f.read()
    t_d = json.loads(data)
    time.sleep(1)
    if t_d.get('ticket') > 0:
        t_d['ticket'] -= 1
        with open('data','w',encoding='utf-8') as f:
            json.dump(t_d,f)
        print('用户%s抢票成功'%i)
    else:
        print('没票了')

def run(i):
    search(i)
    buy(i)

if __name__ == '__main__':
    for i in range(10):  # 生成10个子进程去抢票
        p = Process(target=run,args=(i,))
        p.start()
#这段代码运行之后会出现10个用户都抢到了票的情况,原因是每个用户拿的并不是一个实时的数据,所以在对数据进行修改时,所有人都在对拿到的数据进行修改,所以每个人都将自己拿到的票取了出来(程序中就是将数字减一)

#怎么避免这种情况
from multiprocessing import Process,Lock
import time
import json

# 查票
def search(i):
    with open('data','r',encoding='utf-8') as f:
        data = f.read()
    t_d = json.loads(data)
    print('用户%s查询余票为:%s'%(i,t_d.get('ticket')))

# 买票
def buy(i):
    with open('data','r',encoding='utf-8') as f:
        data = f.read()
    t_d = json.loads(data)
    time.sleep(1)
    if t_d.get('ticket') > 0:
        # 票数减一
        t_d['ticket'] -= 1
        # 更新票数
        with open('data','w',encoding='utf-8') as f:
            json.dump(t_d,f)
        print('用户%s抢票成功'%i)
    else:
        print('没票了')


def run(i,mutex):
    search(i)
    mutex.acquire()  # 抢锁  只要有人抢到了锁 其他人必须等待该人释放锁
    buy(i)
    mutex.release()  # 释放锁


if __name__ == '__main__':
    mutex = Lock()  # 生成了一把锁
    for i in range(10):
        p = Process(target=run,args=(i,mutex))
        p.start()

加锁之后,当一个进程拿到了这个数据的操作权限时,其它进程是无法对这个数据进行操作,甚至无法查看(就是当一个人抢到票在支付的时候其它人是看不到这张票的),其它进程只能等到这个进程的修改操作结束之后才能看到这个数据,然后也是要先抢到锁(所以一次只能有一个人),才能对数据进行修改,当这个进程结束对数据的操作要退出时,会释放锁,这时别的程序才能来抢锁,谁抢到谁来操作。

posted @ 2019-08-10 17:15  云上fly  阅读(294)  评论(0编辑  收藏  举报