开启子进程的两种方式、进程间内存空间隔离、进程对象的方法或属性详解

1、操作系统(推荐查看书籍:现代操作系统)
    操作系统是位于计算机硬件与软件之间的控制程序
    作用:
        1、将硬件的复杂操作封装成简单的接口,给用户或者应用程序使用
        2、将多个应用程序对硬件的竞争变的有序
2、进程
    一个正在运行的程序或者说是一个程序的运行过程
3、串行、并发、并行
    串行:一个任务完完整整运行完毕,才执行下一个程序
    并发:多个任务看起来是同时运行的效果,单核就可以实现并发
    并行:多个任务真正意义上同时运行的效果,多核才可以实现并行
4、多道技术
    背景:想要在单核下实现并发(单核同一时刻只能执行一个任务)
    并发实现的本质就是:切换+保存状态
    多道技术:
        1、空间上的复用——》多个任务共用一个内存条,但占用内存是彼此隔离的,而且是物理层面隔离
        2、时间上的复用——》多个任务共用同一个CPU
           切换:
                1、遇到I/O操作进行切换

                2、一个任务占用CPU时间过长,或者有另外一个优先级更高的任务抢走cpu执行权限

一、进程与程序的区别:

进程是正在进行的一个过程,或者说是一个任务,负责执行任务的是CPU。
程序只是执行 任务背后实施的代码

注意:同一个程序执行两次,是两个进程,如打开两个QQ,一个大号,一个小号,只是进程名一样罢了。

二、并发与并行:

无论是并发还是并行,在用户使用时感觉都差不多,不管是进程还是线程,都只是任务而已,真正驱使任务干活的是cpu,而单个cpu只能同时执行一个任务。

1.并发:是伪并行,看起来是同时运行。单个cpu+多道技术就可以实现并发(并行也属于并发)
2.并行:同时运行,具有多个cpu才能实现并行效果


三、关于创建子进程

    1.相同的是:进程创建后,父进程和子进程都有各自不同的地址空间(多道技术要求物理层面实现进程之间内存的隔离),任何一个进程其在地址空间中的修改都不会影响到另外一个进程。
    2.不同的是:在UNIX中,子进程的初始地址空间是父进程的一个副本。提示:子进程和父进程是可以有只读的共享内存区的。但是对于windows系统来说,从一开始父进程和子进程的地址空间是不同的。

四、进程的终止

1.正常退出(自愿,如用户点击程序上的关闭按钮或者程序执行完毕调用发起系统调用正常退出,在linux用exit,在windows中用ExitProcess)
2.出错退出(自愿,python a.py中a.py不存在)
3.严重错误(非自愿,执行非法指令,如引用不存在的内存,1/0等,可以捕捉异常,try.....except...)
4.被其他进程杀死(非自愿,如kill -9)

五、进程的层次结构

无论UNIX还是windows,只能有一个父进程,不同的区别:
1.UNIX中所有课程都是以init进程为根,组成树形结构。父、子进程共同组成一个进程组,当有信号指令发送过来后会将送达到进程组内所有成员。
2.在windows中,没有进程层次的概念,所有进程都是地位相同的,唯一类似于进程层次的暗示,是在创建进程时,父进程得到一个特别的令牌(称为句柄),该句柄可以用来控制子进程,但是父进程有权把该句柄传给其他子进程,因此没有层次之说。

六、进程的状态

两种情况下会导致一个进程在逻辑上的不能运行:
1、进程挂起是自身原因,遇到I/O阻塞,便要让出CPU为其它进程执行任务,这样就保证CPU随时保持工作状态
2、与进程无关,与操作系统有关。由于一个进程占用时间过长,或者优先级更高任务切换进入等原因,而调用其他的进程去使用CPU

进程具有有有三种状态:

七、进程并发的实现

进程并发的实现在于,硬件中断一个正在运行的进程,把此时进程运行的所有状态保存下来,为此,操作系统维护一张表格,即进程表(process table),每个进程占用一个进程表项(这些表项称为进程控制块)



该表存放了进程状态的重要信息:程序计数器、堆栈指针、内存分配状态、所有打开文件的状态、账号和高度信息,以及其他进程由运行态转为就绪态或阻塞态时,必须保存的信息,从而保证该进程在两次启动时,能够从上一次断开处继续进一步操作,而没有任何影响。

 

python并发编程之多进程

multiprocessing模块:用来开启子进程并在子进程中执行我们定制的任务(比如函数),该模块与多线程模块threading的编程接口类似.
multiprocessing模块的功能众多:支持子进程、通信和共享数据、执行不同形式的同步,提供了Process、Queue、Pipe、Lock等组件。
    需要再次强调的一点是:与线程不同,进程没有任何共享状态,进程修改的数据,改动仅限于该进程内。

创建进程的类:
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类的使用:
注意:在windows中Process()必须放到 # if __name__ == '__main__':下
开启子进程的两种方式
方式一:
from multiprocessing import Process
import time
def task(x):
    print('%s is running' %x)
    time.sleep(3)    #为了出现效果而让子进程睡3秒
    print('%s is done' %x)
if__name__=='__main__':
    #p=Process(target=task,kwargs={'x':'子进程'})    #此例子中不建议使用关键字参数
    p=Process(target=task,args=('子进程,'))    #如果args=(),括号内只有一个参数,一定记住加逗号
    p.start()    #只是在操作系统发送一个开启子进程的信号
    print('主')
结果:
主
子进程 is running
'''期间等待3秒多'''
子进程 is done

方式二:
from multiprocessing import Process
import time
class Myprocess(Process):
    def __init__(self,x):
        super().__init__()
        self.name=x
    def run(self):#固定模版,必须使用
        print('%s is running' %self.name)
        time.sleep(3)
        print('%s is done' %self.name)
if __name__=='__main__':
    p=Process('子进程1')
    p.start()    #p.run()
    print('主')
结果:
主
子进程 is running
'''期间等待3秒多'''
子进程 is done

进程之间的内存空间是隔离的

from multiprocessing import Process
n=100 #在windows系统中应该把全局变量定义在if __name__ == '__main__'之上就可以了
def work():
    global n
    n=0
    print('子进程内: ',n)

if __name__ == '__main__':
    p=Process(target=work)
    p.start()
    print('主进程内: ',n)

孤儿进程及僵尸进程概念:
在unix/linux中,正常情况下,子进程是通过父进程创建的,子进程在创建新的进程。子进程的结束和父进程的运行时
一个异步过程,即父进程永远无法预测子进程到底什么结束。当一个进程完成它的工作终止之后,它的父进程需要调用
wait()或者waitpid()系统调用取得子进程的终止进程。

孤儿进程:一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程。孤儿进程将被init进程(进程号为1)所‘收养’,并由init进程对它们完成状态收集工作。

僵尸进程:一个进程使用fork创建子进程,如果子进程退出,而父进程并没有调用wait或waitpid获取子进程的状态信息,那么子进程的进程描述符仍然保存在系统中。这种进程称之为僵尸进程。

举例:

def task(x,n):
    print('%s is running' % x)
    time.sleep(n)
    print('%s is done' % x)


if __name__ == '__main__':
    # Process(target=task,kwargs={'x':'子进程'})
    p1 = Process(target=task, args=('子进程1',3))  # 如果args=(),括号内只有一个参数,一定记住加逗号
    p2 = Process(target=task, args=('子进程2',5))  # 如果args=(),括号内只有一个参数,一定记住加逗号
    p1.start()  # 只是在操作系统发送一个开启子进程的信号
    p2.start()  # 只是在操作系统发送一个开启子进程的信号

    print('主')
from multiprocessing import Process
import time

x=100
def task():
    global x
    x=0
    print('done')
if __name__ == '__main__':
    p=Process(target=task)
    p.start()
    time.sleep(5) # 让父进程在原地等待,等了5s后,才执行下一行代码
    print(x)

进程对象的方法或属性详解


from multiprocessing import Process
import time
import os

def task():
    # 查看子进程号及父进程号
    print('自己的id:%s 父进程的id:%s ' %(os.getpid(),os.getppid()))
    time.sleep(200)

if __name__ == '__main__':
    p1=Process(target=task)
    p1.start()
    # 查看父进程号及运行此代码的pycharm进程号
    print('主',os.getpid(),os.getppid())
    # 爹=》主--》儿子

了解: 

from multiprocessing import Process,current_process
import time

def task():
    # 查看子进程名
    print('子进程[%s]运行。。。。' %current_process().name) 
    time.sleep(200)

if __name__ == '__main__':
    # 自定义进程名
    p1=Process(target=task,name='子进程1')
    p1.start()
    # 查看子进程名
    # print(p1.name)
    print('主')
from multiprocessing import Process,current_process
import time

def task():
    print('子进程[%s]运行。。。。' %current_process().name)
    time.sleep(2)

if __name__ == '__main__':
    p1=Process(target=task,name='子进程1')
    p1.start()
    # is_alive:查看进程是否存活
    # print(p1.is_alive())
    # p1.join()
    # print(p1.is_alive())
    # 终止进程,terminate和start是应用程序发信号,让操作系统执行操作
    p1.terminate()
    time.sleep(1)
    print(p1.is_alive())
    print('主')

 

你可能感兴趣的:(python基本知识,python,开启子进程的两种方式,进程间内存空间隔离)