操作系统及其进程

一、必备知识

1 操作系统的作用:
    1:隐藏丑陋复杂的硬件接口,提供良好的抽象接口
    2:管理、调度进程,并且将多个进程对硬件的竞争变得有序

2 多道技术:
    1.产生背景:针对单核,实现并发
    ps:
    现在的主机一般是多核,那么每个核都会利用多道技术
    有4个cpu,运行于cpu1的某个程序遇到io阻塞,会等到io结束再重新调度,会被调度到4个
    cpu中的任意一个,具体由操作系统调度算法决定。
    
    2.空间上的复用:如内存中同时有多道程序
    3.时间上的复用:复用一个cpu的时间片
       强调:遇到io切,占用cpu时间过长也切,核心在于切之前将进程的状态保存下来,这样
            才能保证下次切换回来时,能基于上次切走的位置继续运行

二、进程。
  1 在说进程之前我想想讲一下程序,什么是程序?顾名思义,程序就是一堆代码,提到程序我们又必须说下进程,进程就是正在运行的程序。
第一,进程是一个实体,每个进程都有他的地址空间,一般情况下,包括文本区域(text region)、数据区域(data region)和堆栈(stack region)。
文本区域存储处理器执行的代码;
数据区域存储变量和进程执行期间使用的动态分配的内存;堆栈区域存储着活动过程调用的指令和本地变量。 第二,进程是一个“执行中的程序”。程序是一个没有生命的实体,只有处理器赋予程序生命时(操作系统执行之),它才能成为一个活动的实体,我们称其为进程。 第三,进程是操作系统中最基本、重要的概念。是多道程序系统出现后,为了刻画系统内部出现的动态情况,
描述系统内部各道程序的活动规律引进的一个概念,所有多道程序设计操作系统都建立在进程的基础上。

  2 操作系统引入进程概念的原因:目的在于清晰地刻画动态系统的内在规律,有效管理和调度进入计算机系统主存储器运行的程序。

  3 进程的特征:

      动态性:进程的实质是程序在多道程序系统中的一次执行过程,进程是动态产生,动态消亡的。
      并发性:任何进程都可以同其他进程一起并发执行
      独立性:进程是一个能独立运行的基本单位,同时也是系统分配资源和调度的独立单位;
      异步性:由于进程间的相互制约,使进程具有执行的间断性,即进程按各自独立的、不可预知的速度向前推进
      结构特征:进程由程序、数据和进程控制块三部分组成。
      多个不同的进程可以包含相同的程序:一个程序在不同的数据集里就构成不同的进程,能得到不同的结果;但是执行过程中,程序不能发生改变。
  同一个程序执行两次,就会在操作系统中有两个进程,所以我们平时运行同一个软件,分别做不同的事情也不会混乱
  4 进程中的并行和并发:
            并行:两者同时进行,比如龟兔赛跑。并行从是从微观上,也就是在一个精确的时间片刻,有不同的程序在执行,这就要求必须有多个处理器。
            并发:在资源有限的情况下,两者交替轮流使用资源。交替使用,目的是提高效率。并发从宏观上,在一个时间段上可以看出是同时执行的,比如一个服务器同时处理多个session。

 三、同步、异步

  状态介绍:

                                                                

  我们先了解一下进程的几个状态:

  (1)就绪(Ready)状态

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

  (2)执行/运行(Running)状态当进程已获得处理机,其程序正在处理机上执行,此时的进程状态称为执行状态。

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

                                                                

  同步和异步:

   所谓同步就是一个任务的完成需要依赖另外一个任务时,只有等待被依赖的任务完成后,依赖的任务才能算完成,这是一种可靠的任务序列。要么成功都成功,失败都失败,两个任务的状态可以保持一致。

  所谓异步是不需要等待被依赖的任务完成,只是通知被依赖的任务要完成什么工作,依赖的任务也立即执行,只要自己完成了整个任务就算完成了。至于被依赖的任务最终是否真正完成,依赖它的任务无法确定,所以它是不可靠的任务序列

四、进程的创建与结束 

  对于通用系统(跑很多应用程序),需要有系统运行过程中创建或撤销进程的能力,主要分为4中形式创建新的进程:

  1. 系统初始化(查看进程linux中用ps命令,windows中用任务管理器,前台进程负责与用户交互,后台运行的进程与用户无关,运行在后台并且只在需要时才唤醒的进程,称为守护进程,如电子邮件、web页面、新闻、打印)

  2. 一个进程在运行过程中开启了子进程(如nginx开启多进程,os.fork,subprocess.Popen等)

  3. 用户的交互式请求,而创建一个新进程(如用户双击暴风影音)

  4. 一个批处理作业的初始化(只在大型机的批处理系统中应用)

  无论哪一种,新进程的创建都是由一个已经存在的进程执行了一个用于创建进程的系统调用而创建的

  进程的结束:     

  1. 正常退出(自愿,如用户点击交互式页面的叉号,或程序执行完毕调用发起系统调用正常退出,在linux中用exit,在windows中用ExitProcess)

  2. 出错退出(自愿,python a.py中a.py不存在)

  3. 严重错误(非自愿,执行非法指令,如引用不存在的内存,1/0等,可以捕捉异常,try...except...)

  4. 被其他进程杀死(非自愿,如kill -9

五、multiprocess模块

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

Process([group [, target [, name [, args [, kwargs]]]]]),由该类实例化得到的对象,表示一个子进程中的任务(尚未启动)

强调:
1. 需要使用关键字的方式来指定参数
2. args指定的为传给target函数的位置参数,是一个元组形式,必须有逗号

参数介绍:
1 group参数未使用,值始终为None
2 target表示调用对象,即子进程要执行的任务
3 args表示调用对象的位置参数元组,args=(1,2,'egon',)
4 kwargs表示调用对象的字典,kwargs={'name':'egon','age':18}
5 name为子进程的名称

  方法介绍:

1 p.start():启动进程,并调用该子进程中的p.run() 
2 p.run():进程启动时运行的方法,正是它去调用target指定的函数,我们自定义类的类中一定要实现该方法  
3 p.terminate():强制终止进程p,不会进行任何清理操作,如果p创建了子进程,该子进程就成了僵尸进程,使用该方法需要特别小心这种情况。如果p还保存了一个锁那么也将不会被释放,进而导致死锁
4 p.is_alive():如果p仍然运行,返回True
5 p.join([timeout]):主线程等待p终止(强调:是主线程处于等的状态,而p是处于运行的状态)。timeout是可选的超时时间,需要强调的是,p.join只能join住start开启的进程,而不能join住run开启的进程  

  

1 p.daemon:默认值为False,如果设为True,代表p为后台运行的守护进程,当p的父进程终止时,p也随之终止,并且设定为True后,p不能创建自己的新进程,必须在p.start()之前设置
2 p.name:进程的名称
3 p.pid:进程的pid
4 p.exitcode:进程在运行时为None、如果为–N,表示被信号N结束(了解即可)
5 p.authkey:进程的身份验证键,默认是由os.urandom()随机生成的32字符的字符串。这个键的用途是为涉及网络连接的底层进程间通信提供安全性,这类连接只有在具有相同的身份验证键时才能成功(了解即可)

  process创建进程

  方式一:

from multiprocessing import Process
import time


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

"""
windows创建进程会将代码以模块的方式 从上往下执行一遍
linux会直接将代码完完整整的拷贝一份
windows创建进程一定要在if __name__ == '__main__':代码块内创建  否则报错
"""
if __name__ == '__main__':
    p = Process(target=test,args=('egon',))  # 创建一个进程对象
    p.start()  # 告诉操作系统帮你创建一个进程
    print('主')

  方式二:

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('主')

  join方法:

from multiprocessing import Process
import time

def test(name,i):
    print('%s is running'%name)
    time.sleep(i)
    print('%s is over'%name)
if __name__ == '__main__':
    p_list = []
    # for i in range(3):
    #     p = Process(target=test,args=('进程%s'%i,i))
    #     p.start()
    #     p_list.append(p)
    # for p in p_list:
    #     p.join()
    p = Process(target=test,args=('egon',1))
    p1 = Process(target=test,args=('kevin',2))
    p2 = Process(target=test,args=('jason',3))
    start_time = time.time()
    p.start()  # 仅仅是告诉操作系统帮你创建一个进程 至于这个进程什么时候创  操作系统随机决定
    p1.start()
    p2.start()
    p2.join()
    p.join()
    p1.join()

    # 主进程代码等待子进程运行结束 才继续运行
    # p.join()  # 主进程代码等待子进程运行结束
    print('主')
    print(time.time() - start_time)

  进程对象及其他方法:

from multiprocessing import Process,current_process
import os
import time


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


if __name__ == '__main__':
    p = Process(target=test,args=('egon',))
    p.start()
    p.terminate()  # 杀死当前进程  其实是告诉操作系统帮你杀死一个进程
    time.sleep(0.1)
    print(p.is_alive())  # 判断进程是否存活
    # print('主',current_process().pid)
    print('主',os.getpid(),'主主进程:%s'%os.getppid())

  守护进程:

  主程序守护子程序,如果主程序运行结束,就不会再执行子程序,跟时间有关系,当触发start的时间小于主进程睡的时间时,就会执行子进程。

from multiprocessing import Process
import time


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


if __name__ == '__main__':
    p = Process(target=test,args=('egon',))
    p.daemon = True  # 将该进程设置为守护进程   这一句话必须放在start语句之前 否则报错
    p.start()
    time.sleep(0.1)
    print('皇帝jason寿正终寝')

  互斥锁:

    当多个进程操作同一份数据的时候,就会造成数据的错乱,这个时候必须进行加锁处理,将并发变成了串行,虽然降低了效率,但是提高了数据的安全性,锁必须在主进程中使用,交给子进程去使用。

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()

  

猜你喜欢

转载自www.cnblogs.com/panshao51km-cn/p/11333593.html