'''
multiprocessing模块提供了一个Process类来代表一个进程对象，
下面的例子演示了启动一个子进程并等待其结束.

[Process类中各方法的介绍]：
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开启的进程

p.join()让主进程在加上join的地方等待（也就是阻塞住，注意只有自己能阻塞自己），等待子进程执行完之后，再继续往下执行我的主进程，
好多时候，我们主进程需要子进程的执行结果，所以必须要等待。join感觉就像是将子进程和主进程拼接起来一样，将异步改为同步执行。

[Process类中自带封装的各属性的介绍]:
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字符的字符串。
这个键的用途是为涉及网络连接的底层进程间通信提供安全性，
这类连接只有在具有相同的身份验证键时才能成功（了解即可）


通过主进程创建的子进程是异步执行的，那么我们就验证一下，
并且看一下子进程和主进程(也就是父进程)的ID号，来看看是否是父子关系。

#当前文件名称为process.py
'''

import time
import os

#os.getpid()  获取自己进程的ID号
#os.getppid() 获取自己进程的父进程的ID号

from multiprocessing import Process

def func():
    print('aaaa')
    time.sleep(1)
    print('子进程>>',os.getpid())
    print('该子进程的父进程>>',os.getppid())
    print(12345)

if __name__ == '__main__':
    #首先我运行当前这个文件，运行的这个文件的程序，那么就产生了主进程。
    p = Process(target=func,)
    p.start()
    print('*' * 10)
    print('父进程>>',os.getpid())
    print('父进程的父进程>>',os.getppid())
    #Output
    '''
    **********
    父进程>> 8828  #主进程的ID号
    父进程的父进程>> 5264 #运行的process_test.py文件的父进程号
    aaaa
    子进程>> 9504
    该子进程的父进程>> 8828   #主进程的ID号
    12345

    [Output 解读]
    首先打印出来了主进程的程序，然后打印的是子进程的，虽然在代码中子进程start在这些打印命令前，
    但是子进程打印的结果却在后面，所以说明子进程是异步执行的，相当于主进程和子进程同时运行着。

    如果是同步的话，我们先执行的是func()，然后再打印主进程最后的10个*号。
    '''
