031_进程

操作系统的发展

详情见:操作系统的发展史

# 操作系统发展
   # 没有操作系统 —— 穿孔卡片
    #  批处理系统  —— 串行 ,速度块
    #  联机批处理 —— 读磁带的时候速度快
    #  脱机批处理 —— 读磁带和cpu工作并发
  # 多道程序系统 —— 并行
    #  操作系统的各种管理功能
    #  时空的复用 : 空间隔离开来,cpu看起来可以处理多个任务
  # 分时系统 —— 更好的实现了 并行
    #  让cpu的工作效率下降了
  # 实时系统 —— 对一个任务实时响应
    # 优点:快
    # 缺点 :能处理的任务更少
  # 通用操作系统
    # 兼具多个操作系统的特性
 
# 操作系统的功能
  # 封装了对硬件的操作过程,给应用程序提供好用的接口
  # 对多个作业进行调度管理来分配硬件资源
 
什么是进程
 
  进程(Process是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。在早期面向进程设计的计算机结构中,进程是程序的基本执行实体;在当代面向线程设计的计算机结构中,进程是线程的容器。程序是指令、数据及其组织形式的描述,进程是程序的实体。—— 百度百科
 
1,进程的概念主要有两点:
    第一:进程是一个实体。每一个进程都有它自己的地址空间,一般情况下,包括文本区域(text region)、数据区域(data region)和堆栈(stack region)。文本区域存储处理器执行的代码;数据区域存储变量和进程执行期间使用的动态分配的内存;堆栈区域存储着活动过程调用的指令和本地变量。
    第二:进程是一个“执行中的程序”。程序是一个没有生命的实体,只有处理器赋予程序生命时(操作系统执行之),它才能成为一个活动的实体,我们称其为进程
  
  进程是操作系统中最基本、重要的概念。是多道程序系统出现后,为了刻画系统内部出现的动态情况,描述系统内部各道程序的活动规律引进的一个概念,所有多道程序设计操作系统都建立在进程的基础上。
从理论角度看,是对正在运行的程序过程的抽象;
从实现角度看,是一种数据结构,目的在于清晰地刻画动态系统的内在规律,有效管理和调度进入计算机系统主存储器运行的程序。
操作系统引入进程的概念的原因

 

2,特征:

    动态性:进程的实质是程序在多道程序系统中的一次执行过程,进程是动态产生,动态消亡的。
    并发性:任何进程都可以同其他进程一起并发执行
    独立性:进程是一个能独立运行的基本单位,同时也是系统分配资源和调度的独立单位;
    异步性:由于进程间的相互制约,使进程具有执行的间断性,即进程按各自独立的、不可预知的速度向前推进
    结构特征:进程由程序、数据和进程控制块三部分组成。
    多个不同的进程可以包含相同的程序:一个程序在不同的数据集里就构成不同的进程,能得到不同的结果;但是执行过程中,程序不能发生改变
 
3,状态:  
    1)就绪状态(Ready)
    进程已获得除处理器外的所需资源,等待分配处理器资源;只要分配了处理器进程就可执行。就绪进程可以按多个优先级来划分队列。例如,当一个进程由于时间片用完而进入就绪状态时,排入低优先级队列;当进程由I/O操作完成而进入就绪状态时,排入高优先级队列。
    2)运行状态(Running):
    进程占用处理器资源;处于此状态的进程的数目小于等于处理器的数目。在没有其他进程可以执行时(如所有进程都在阻塞状态),通常会自动执行系统的空闲进程。
    3)阻塞状态(Blocked):
    由于进程等待某种条件(如I/O操作或进程同步),在条件满足之前无法继续执行。该事件发生前即使把处理器资源分配给该进程,也无法运行。
 
4,区别:
  程序
    程序是指令和数据的有序集合,其本身没有任何运行的含义,是一个静态的概念。而进程是程序在处理机上的一次执行过程,它是一个动态的概念。
    程序可以作为一种软件资料长期存在,而进程是有一定生命期的。程序是永久的,进程是暂时的。
进程更能真实地描述并发,而程序不能;
    进程是由进程控制块程序段、数据段三部分组成;
    进程具有创建其他进程的功能,而程序没有。
    同一程序同时运行于若干个数据集合上,它将属于若干个不同的进程,也就是说同一程序可以对应多个进程。
    在传统的操作系统中,程序并不能独立运行,作为资源分配和独立运行的基本单元都是进程。
5,线程 
    通常在一个进程中可以包含若干个线程,它们可以利用进程所拥有的资源,在引入线程操作系统中,通常都是把进程作为分配资源的基本单位,而把线程作为独立运行和独立调度的基本单位,由于线程比进程更小,基本上不拥有系统资源,故对它的调度所付出的开销就会小得多,能更高效的提高系统内多个程序间并发执行的程度。
    当下推出的通用操作系统都引入了线程,以便进一步提高系统的并发性,并把它视为现代操作系统的一个重要指标。
 
 
6,进程的调度算法
  实时系统中:
    FIFO(First Input First Output,先进先出算法),
    SJF(Shortest Job First,最短作业优先算法),
    SRTF(Shortest Remaining Time First,最短剩余时间优先算法)。
 
  交互式系统中:
    RR(Round Robin,时间片轮转算法),
    HPF(Highest Priority First,最高优先级算法),多级队列,最短进程优先,保证调度,彩票调度,公平分享调度。
 
7,同步异步:
  # 异步  只管调度 不等结果 (多条线,互不干扰)
  # 同步  调度之后 还一定要等到结果 (一条线上)

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

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

8,阻塞与非阻塞:

    阻塞和非阻塞这两个概念与程序(线程)等待消息通知(无所谓同步或者异步)时的状态有关。也就是说阻塞与非阻塞主要是程序(线程)等待消息通知时的

  同步阻塞形式

  异步阻塞形式

  同步非阻塞形式

  异步非阻塞形式

9,创建进程

  但凡是硬件,都需要有操作系统去管理,只要有操作系统,就有进程的概念,就需要有创建进程的方式,一些操作系统只为一个应用程序设计,比如微波炉中的控制器,一旦启动微波炉,所有的进程都已经存在。

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

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

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

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

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

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

1. 在UNIX中该系统调用是:fork,fork会创建一个与父进程一模一样的副本,二者有相同的存储映像、同样的环境字符串和同样的打开文件(在shell解释器进程中,执行一个命令就会创建一个子进程)

  2. 在windows中该系统调用是:CreateProcess,CreateProcess既处理进程的创建,也负责把正确的程序装入新进程。

  关于创建子进程,UNIX和windows

  1.相同的是:进程创建后,父进程和子进程有各自不同的地址空间(多道技术要求物理层面实现进程之间内存的隔离),任何一个进程的在其地址空间中的修改都不会影响到另外一个进程。

  2.不同的是:在UNIX中,子进程的初始地址空间是父进程的一个副本,提示:子进程和父进程是可以有只读的共享内存区的。但是对于windows系统来说,从一开始父进程与子进程的地址空间就是不同的。
创建进程

10,进程的结束

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

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

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

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

 

 在python程序中的进程操作

1,查看进程的 PID 号

  每一个进程都有一个自己的 PID 号,可以在任务管理器,详细信息中找到这个进程。

import os
import time
print(os.getpid())  # 获取当前运行的python程序的进程id  process id
print(os.getppid()) # parent process id 获取当前进程的父id
time.sleep(100)

2, python当中创建进程来替我做事情

  multiprocess 模块:multiple [ˈmʌltɪpl]  adj.  数量多的;多种多样的  n. 倍数 

             process  [prəˈses] n. 过程;进程;

  仔细说来,multiprocess不是一个模块而是python中一个操作、管理进程的包。 在这个包中几乎包含了和进程有关的所有子模块。由于提供的子模块非常多,为了方便归类记忆,将这部分大致分为四个部分:创建进程部分,进程同步部分,进程池部分,进程之间数据共享。

3,其中的 process 模块介绍

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

  创建的是子进程

  3.1,参数介绍:

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为子进程的名称 

  3.2,方法介绍:

  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开启的进程  

  3.3,属性介绍:

  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字符的字符串。这个键的用途是为涉及网络连接的底层进程间通信提供安全性,这类连接只有在具有相同的身份验证键时才能成功(了解即可)

   3.4,在windows中使用process模块的注意事项

  在Windows操作系统中由于没有fork(linux操作系统中创建进程的机制),在创建子进程的时候会自动 import 启动它的这个文件,而在 import 的时候又执行了整个文件。因此如果将process()直接写在文件中就会无限递归创建子进程报错。所以必须把创建子进程的部分使用if __name__ ==‘__main__’ 判断保护起来,import 的时候  ,就不会递归运行了。

4,使用 process 模块创建子进程 

  4.1 ,创建第一个子进程

from multiprocessing import Process
def func():
    print(123)
    print('我是子进程')

if __name__ == '__main__':
    p = Process(target=func )     # 创建一个进程对象
    p.start()  		# 直到执行start才有了进程
    print('执行主进程的内容了')

# windows操作系统中 创建进程的语句一定要放在if __name__ == '__main__':条件语句下面
# 因为windows操作系统在创建子进程的时候会将文件整个从新执行,放在外面就会,不断的创建子进程,成递归。

  4.2,验证并不是一个进程

import os
from multiprocessing import Process
def func():
    print('子进程',os.getpid())
    print(123)

if __name__ == '__main__':
    p = Process(target=func )     # 创建一个进程对象
    print('主进程',os.getpid())
    p.start()  
    print('主进程',os.getpid())

# 结果
主进程  4552
主进程  4552 
子进程  6024

  4.3,为什么不是打印  主,子,主?

    在执行p.start()时,只是告诉操作系统我要创建进程,并不等待结果。两个进程是异步的。

5,这是一个同步的进程

from multiprocessing import Process
def func():
      print(123)

if __name__ == '__main__':
    func()

6,异步阻塞

  两个进程是异步的

import os
import time
from multiprocessing import Process
def func():
      print('子进程',os.getpid())
      print(123)

if __name__ == '__main__':
    p = Process(target=func )     # 创建一个进程对象
    print('主进程',os.getpid())
    p.start()          # 子进程执行
    time.sleep(10)      # 主程序发生阻塞
    print('取完钱了')
# 主进程阻塞,不影响子进程的执行

7,同步阻塞

import time
def func():
      print(123)

if __name__ == '__main__':
    time.sleep(10)      # 发生阻塞 ,等待结果
    func()
    print('取完钱了')

8,传参,执行顺序

import os
import time
from multiprocessing import Process
def func(money):
      time.sleep(3)
      print('取钱 :%d'%money)
      

if __name__ == '__main__':
    p = Process(target=func,args=(1,) )     # 可以给子进程传参,但必须传的是一个元组
    p.start()			#只传一个值时后面也要跟一个逗号。
    print('取完钱了')

  # 异步进程,虽然子进程并没有结束(没有取完钱)但是主进程已经向后执行(打印取完钱了)
  # 虽然是异步进程,两进程的执行互不干扰,但是如果子进程没有执行完,即便主进程已经执行完,主进程也不会结束。只有子进程执行完才会结束主进程。

9,解决上面的问题   join方法

import os
import time
from multiprocessing import Process
def func(money):
      time.sleep(3)
      print('取钱 :%d'%money)
      

if __name__ == '__main__':
    p = Process(target=func,args=(1,) )     
    p.start()
    p.join()   # p.join 就是主进程会阻塞在join的位置,等待p进程结束			
    print('取完钱了')

  # 但是,这样又将程序阻塞,变成类似于同步

10,开启多个子线程 和 join 的使用

import os
from multiprocessing import Process
def func():
    print('%d :子进程%d干的事儿,父进程:%d'%(i,os.getpid(),os.getppid()))

if __name__ == '__main__':
    p = Process(target=func)
    p1 = Process(target=func)
    p2 = Process(target=func)
    p.start()
    p1.start()
    p2.start()
#   p.join()    # 此处加上这一句,意味着,只有p子进程结束才能执行后面的。但不管其他子进程。
    print('------主进程------')

11,join 的使用

import os
import time
from multiprocessing import Process
def func(i):
    time.sleep(1)
    print('%d :子进程%d干的事儿,父进程:%d'%(i,os.getpid(),os.getppid()))

  11.1,

if __name__ == '__main__':
    # 100
    for i in range(10):
        p = Process(target=func,args=(i,))
        p.start()        # 创建的子进程,执行的顺序是无序的
     p.join()         # 只会管最后一个创建的子进程,其他的而不管。
	          # 后面的程序,会在最后一个创建的子进程结束后才执行 
    # join如果放在for里面,就会是创建一个子程序,并且执行完之后才在创建新的子程序。
    print('------主进程------')   

  11.2,让最后一句话在所有子进程执行完后在打印。

if __name__ == '__main__':
    # 100
    p_lst = []
    for i in range(10):
        p = Process(target=func,args=(i,))
        p.start()
        p_lst.append(p)
    for p in p_lst:
        p.join()
    print('------主进程------')

12,另一种开启进程的方式

import os
from multiprocessing import Process
class MyProcess(Process):

    def run(self):       
        print('子进程:%d'%os.getpid())
        self.walk()  # --->在子进程中调用

    def walk(self):       # 自定义的 可以不定义
        print('子进程:%d' % os.getpid())

if __name__ == '__main__':
    p = MyProcess()
    p.start()        # --->   # start会自动调用run方法
    # p.walk()     # --->  在主进程中调用
    print('主进程 :',os.getpid())
# 必须创建一个类 必须继承Process类
# 必须实现一个run方法

  12.1,传参形式

import os
from multiprocessing import Process
class MyProcess(Process):
    def __init__(self,arg1,arg2):     # 传参
        super().__init__()
        self.arg1 = arg1
        self.arg2 = arg2

    def run(self):
        print('子进程:%d,%s,%s'%(os.getpid(),self.arg1,self.arg2))
        self.walk()  # --->在子进程中调用

    def walk(self): # 自定义的 可以不定义
        print('子进程:%d' % os.getpid())

if __name__ == '__main__':
    p = MyProcess(1,2)
    p.start()    # --->  run方法
    # p.walk()     # --->  在主进程中调用
    print('主进程 :',os.getpid())

13, 数据隔离

  # 进程与进程之间的数据是隔离的,不共享的

from multiprocessing import Process
n = 100
def func():
    global n
    n = n - 1
    print(n)
if __name__ == '__main__':
    for i in range(10):
        p = Process(target=func)
        p.start()
        p.join()
    print('主进程 :',n)

14, 进程操作实例

import socket 
from multiprocessing import Process

def talk(conn):
    conn.send(b'connected')
    ret = conn.recv(1024)
    print(ret)

if __name__ == '__main__':
    sk = socket.socket()
    sk.bind(('127.0.0.1', 8080))
    sk.listen()
    while True:
        conn,addr = sk.accept()
        p = Process(target=talk,args=(conn,))
        p.start()
    conn.close()
    sk.close()
sever端
import socket
sk = socket.socket()
sk.connect(('127.0.0.1',8080))
ret = sk.recv(1024)
print(ret)
msg = input('>>>')
sk.send(msg.encode('utf-8'))
sk.close()
client端

 

posted @ 2019-04-17 11:03  冰羽~zZ  阅读(175)  评论(0编辑  收藏  举报