进程

进程

一、基础

  • 进程三态状态转换图:
graph TB A[创建]--提交-->B[就绪] B[就绪]--进程调度-->C[运行] C[运行]--时间片到-->B[就绪] C{运行}--释放资源-->D[退出] C{运行}--事件请求-->E[阻塞] E[阻塞]--保存现场-->F[发生阻塞的进程数据存储到栈] F[发生阻塞的进程数据存储到栈]--恢复现场-->B[就绪]

注意:

  • 栈是一种数据的存储方式,基本的特点是先进后出,具有这种特点的统称为栈。
  • 计算机中栈的一般大小是几个兆,如果希望拿出先进的数据,必须把它后进的数据全部取出之后才能拿出需要的数据。
  • 每个进程都有自己的堆和栈,但是具体的大小是受操作系统影响的。如果不是人为的干预,一般进程之间不会共同一个空间
  • 同步与异步:
    • 同步:一个任务的完成需要依赖另外一个任务,只有等待被依赖的任务完成之后,该任务才可以完成,这是一种可靠的任务序列。要么都成功,要么都失败,两个任务的状态保持一致。
    • 异步:不需要等待被依赖任务的完成,只是通知被依赖任务需要完成什么工作,依赖的任务也立即执行,只要自己完成了整个任务就算完成了。至于被依赖的任务是否真正的完成,依赖它的任务无法确定,所以异步是不可靠的任务序列。
  • 阻塞和非阻塞:
    阻塞和非阻塞这两个概念与程序(线程)等待消息通知(无所谓同步或者异步)时的状态有关,也就是说阻塞和非阻塞主要是程序(线程)等待消息通知时的状态角度来说的。
    同步/异步与阻塞/非阻塞分类:
    • 同步阻塞,效率最低
    • 异步阻塞
    • 同步非阻塞
    • 异步非阻塞,效率最高

二、多进程的开启方式及方法

(一)、直接实例化对象开启
  • 导入:from multiprocessing import Process
  • 创建需要开启程序进行运行的程序
  • if name == 'main': 这个是必须要用到的,如果不用会报错。
  • 实例化一个进程对象:p = Process(target=需要开启进程的函数名/类名,args=(函数的参数)),这个参数必须是元祖形式的。
  • 开启进程:p.start()

os.getpid获取当前进程的进程号,os.getppid获取当前进程的父亲进程的进程号。

from multiprocessing import Process
import time
import os
list = [('liuyang', 20), ('lili', 21)]
def func(name, age):
    print('学生%s的年龄为%d' % (name, age))
    time.sleep(1)
    print('这里是儿子进程,进程pid为%d,父亲进程的pid为%d' % (os.getpid(), os.getppid()))

if __name__ == '__main__':
    for info in list:
        p = Process(target=func, args=info)
        p.start()
    print('这里是父亲进程,父亲进程的pid为%d,父亲的父亲进程的pid为%d' % (os.getpid(), os.getppid()))

'''
结果是:
学生liuyang的年龄为20
这里是父亲进程,父亲进程的pid为3260,父亲的父亲进程的pid为2929
学生lili的年龄为21
这里是儿子进程,进程pid为3261,父亲进程的pid为3260
这里是儿子进程,进程pid为3262,父亲进程的pid为3260

'''
(二)、通过继承线程类来开启
  • 导入:from multiprocessing import Process
  • 创建继承类Myprocess()
  • if name == 'main': 这个是必须要用到的,如果不用会报错。
  • 实例化一个进程对象:p = Process(参数)
  • 开启进程:p.start()
from multiprocessing import Process
import os

class Myprocess(Process):
    def __init__(self, name, age):
        super().__init__()
        self.name = name
        # Process类中也有name参数,如果这个写在了super()前边,父类中的name就会覆盖掉本类中的name,这点需要注意
        self.age = age

    def get_info(self):
        print('学生%s的年龄为%d' % (self.name, self.age))
        print('子进程的pid为%d, 父进程的pid为%d' % (os.getpid(), os.getppid()))
        return '执行结束'


if __name__ == '__main__':
    p = Myprocess('黎明', 34)
    p.start()
    print(p.get_info())
    print('子进程的进程号为%d, 父进程的进程号为%d' % (os.getpid(), os.getppid()))

'''
结果是:
学生黎明的年龄为34
子进程的pid为3992, 父进程的pid为2929
执行结束
子进程的进程号为3992, 父进程的进程号为2929
'''

p.run()和p.start()的效果都是一样的,开启一个进程。区别在于:start()是解释器告诉操作系统给我开一个进程,在就绪状态,而run()则是解释器告诉操作系统马上给我执行这个进程。start()底层调用的是run()方法。

(三)、time.sleep()和p.join()用法
  • time.sleep()是把当前进行的进程阻塞住,,是的CPU可以去执行其他的进程,阻塞多长时间可以自己设定
from multiprocessing import Process
import time

def func():
    for i in range(10):
        time.sleep(0.1)
        # sleep()的作用是造成当前进程阻塞
        print('这是子进程')

if __name__ == '__main__':
    p = Process(target=func)
    p.start()
    for i in range(10):
        time.sleep(0.1)
        print('这是父进程')

'''
结果是:
这是父进程
这是子进程
这是子进程
这是父进程
这是子进程
这是父进程
这是父进程
这是子进程
这是父进程
这是子进程
这是父进程
这是子进程
这是父进程
这是子进程
这是父进程
这是子进程
这是父进程
这是子进程
这是父进程
这是子进程
'''
# 子进程和父进程交替执行

需要特别注意的是:主进程和子进程正常情况下是同时在执行的,但是具体怎么执行程序控制不料,由操作系统来处理,除非人为的添加阻塞程序。

  • join()方法
    join()的作用就是把主进程阻塞住,让系统先执行子进程,子进程执行完之后再执行主进程。使用的情景:同步,当主进程的执行必须依赖于子进程返回的结果的时候,才用到p.join()方法。不加join()就是异步。join()必须放在start()后边,即必须在主进程开启之后才能使用。
from multiprocessing import Process
import time

def func():
    for i in range(10):
        time.sleep(0.1)
        # sleep()的作用是造成当前进程阻塞
        print('这是子进程')

if __name__ == '__main__':
    p = Process(target=func)
    p.start()
    p.join()
    # join()的作用就是把主进程阻塞住,让系统先执行子进程
    for i in range(10):
        print('这是父进程')

'''结果是:
这是子进程
这是子进程
这是子进程
这是子进程
这是子进程
这是子进程
这是子进程
这是子进程
这是子进程
这是子进程
这是父进程
这是父进程
这是父进程
这是父进程
这是父进程
这是父进程
这是父进程
这是父进程
这是父进程
这是父进程
'''
# 系统先执行了子进程,后执行主进程
(四)、p.terminate()和p.is_alive()方法
  • p.terminate()方法的作用是让python解释器告诉操作系统强制杀死子进程,只执行主进程。这个方法需要慎用,如果使用该方法把子进程杀死之后,不会进行清理,创建的子进程也就成为了死锁。
  • p.alive()方法的作用是判断进程是否被杀死,如果返回为True,表示进程没有被杀死,如果返回为False,表示的是进程已经被杀死。
from multiprocessing import Process
import time

def func():
    for i in range(5):
        time.sleep(0.1)
        # sleep()的作用是造成当前进程阻塞
        print('这是子进程')

if __name__ == '__main__':
    p = Process(target=func)
    p.start()
    p.terminate()
    # python解释器告诉操作系统杀死子进程
    for i in range(5):
        print('这是父进程')
        time.sleep(0.01)
        # 这里必须用time.sleep()来造成阻塞,否则无法杀死进程
        print(p.is_alive())
        # 判断进程是否被杀死
'''
这是父进程
False
这是父进程
False
这是父进程
False
这是父进程
False
这是父进程
False
'''

三、属性设置

  • p.name = '名字': 可以设置进程的名字属性

  • p.daemon = True:设置为守护进程,默认为False

    • 守护进程不允许创建自己的子进程
    from multiprocessing import Process
    import time
    
    def func1():
        print('这是子进程开启的子进程')
    
    def func():
        for i in range(5):
            print(time.strftime('%H:%M:%S'))
            time.sleep(5)
            # sleep()的作用是造成当前进程阻塞
            p = Process(target=func1)
            p.start()
            time.sleep(2)
            print('这是父进程开启的子进程')
    
    
    if __name__ == '__main__':
        p = Process(target=func)
        p.daemon = True
        p.start()
    
        for i in range(5):
            print('这是父进程')
            time.sleep(1)
        p.join()
    
    '''结果是:
    这是父进程
    08:55:54
    这是父进程
    这是父进程
    这是父进程
    这是父进程
    Process Process-1:
    Traceback (most recent call last):
      File "/usr/lib/python3.6/multiprocessing/process.py", line 258, in _bootstrap
        self.run()
      File "/usr/lib/python3.6/multiprocessing/process.py", line 93, in run
        self._target(*self._args, **self._kwargs)
      File "open-multiprocessing.py", line 112, in func
        p.start()
      File "/usr/lib/python3.6/multiprocessing/process.py", line 103, in start
        'daemonic processes are not allowed to have children'
    AssertionError: daemonic processes are not allowed to have children
    '''
    
    
    • 当设置为守护进程时,只执行主进程,不执行子进程。即守护进程随着主进程(父进程)的结束而结束。
    from multiprocessing import Process
    import time
    
    def func1():
        print('这是子进程开启的子进程')
    
    def func():
        for i in range(5):
            print(time.strftime('%H:%M:%S'))
            print('这是父进程开启的子进程')
    
    
    if __name__ == '__main__':
        p = Process(target=func)
        p.daemon = True
        # 设置守护进程
        p.start()
    
        for i in range(5):
            print('这是父进程')
    
    '''结果是:
    这是父进程
    这是父进程
    这是父进程
    这是父进程
    这是父进程
    '''
    
    
    • 在主进程中添加p.join()方法可以让守护进程运行子进程,但是子进程依然不能创建自己的子进程。
    from multiprocessing import Process
    import time
    
    def func1():
        print('这是子进程开启的子进程')
    
    def func():
        for i in range(5):
            print(time.strftime('%H:%M:%S'))
            time.sleep(5)
            # sleep()的作用是造成当前进程阻塞
            # p = Process(target=func1)
            # p.start()
            time.sleep(2)
            print('这是父进程开启的子进程')
    
    
    if __name__ == '__main__':
        p = Process(target=func)
        p.daemon = True
        p.start()
    
        for i in range(5):
            print('这是父进程')
            time.sleep(1)
        p.join()
    
    '''
    结果是:
    这是父进程
    08:56:24
    这是父进程
    这是父进程
    这是父进程
    这是父进程
    这是父进程开启的子进程
    08:56:31
    这是父进程开启的子进程
    08:56:38
    这是父进程开启的子进程
    08:56:45
    这是父进程开启的子进程
    08:56:52
    这是父进程开启的子进程
    
    '''
    

p.daemon = Ture必须设置在p.start()之前才能生效。

posted @ 2020-03-04 21:31  大道至诚  阅读(199)  评论(0编辑  收藏  举报