小结

回顾及今日内容

'''
操作系统
*****
串行:一个进程完完整整执行完再执行下一个
并发:看起来是同时运行  单核
并行:真正的同时运行

多道技术:
空间复用:共用一个内存条,多个进程互相隔离,物理级别隔离
时间复用:共用一个cpu


*****
程序:躺在硬盘上的文件
进程:一个执行的程序,是一系列资源的总和
如何在我们的进程里开子进程


# 尽量减少阻塞状态可以提升我们的程序运行效率

*****
并发 = 保存状态 + 切换
'''

#*****
# 开子进程  申请新的内存空间,把父进程的所有代码完整拷贝一份过去
# 方式一
from multiprocessing import Process

def task(x):
    pass

if __name__ == '__main__':
    p = Process(target=task, args=(5,))
    p.start()

# 方式二(不常用)
from multiprocessing import Process

class Task(Process):
    def __init__(self, name):
        super().__init__()
        self.name = name
    def run(self):
        pass
p = Task('Nick')
p.start()

# 验证内存空间彼此隔离

#僵尸进程:父进程的子进程结束的时候父进程没有wait()情况下子进程会变成僵尸进程

#####################今日内容############
# 孤儿进程(无害的)* 就算父进程没有回收,__init__也会统一回收
# 一个父进程退出,而它的一个或多个子进程还在运行,那么那些进程会变成孤儿进程。孤儿进程将被init进程(进程号为1)所收养,并由init进程对它们完成状态收集收集工作
'''
情况1  无害
父进程等着子进程都死完,回收僵尸进程

情况2  无害
父进程死了, 子进程活着,都要被init进程接管并且回收

情况3
父进程一直不死,造成了大量僵尸进程。占用大量的pid号
pid号是有限的
解决方案:
最直接的办法就是杀死父进程
'''

# join 的用法*****

# Process的其它小用法*

# 掌握pid 和 ppid的查看方式 *****

# 守护进程 *****
# 抢票小程序

Process的join的用法

from multiprocessing import Process
import time
# def foo():
#     print('子进程 start')
#     time.sleep(2)
#     print('子进程 end')
#
# if __name__ == '__main__':
#     p = Process(target=foo)
#     p.start()
#     #time.sleep(5)  现在不用time.sleep ,使用Process的join方法
#     p.join() ## 阻塞住主进程在等待子进程结束,然后再往下执行(内部会调用wait())
#     print('主进程')

# from multiprocessing import Process
# import time
#
# def foo(x):
#     print('子进程 start')
#     time.sleep(x)
#     print('子进程 end')
#
# if __name__ == '__main__':
#     p = Process(target=foo, args=(1,))
#     p2 = Process(target=foo, args=(2,))
#     p3 = Process(target=foo, args=(3,))
#
#     start = time.time()
#     p.start()
#     p2.start()
#     p3.start()
#
#     p.join()
#     p2.join()
#     p3.join()
#     # 总时长:按照最长的时间计算多一点
#     end = time.time()
#     print(end - start) #3.579204797744751
#     print('主进程')

from multiprocessing import Process
import time

def foo(x):
    print(f'进程{x} start')
    time.sleep(x)
    print(f'子进程{x} end')

if __name__ == '__main__':
    p = Process(target=foo, args=(1,))
    p2 = Process(target=foo, args=(2,))
    p3 = Process(target=foo, args=(3,))
    start = time.time()
    # p.start()
    # p.join()
    # p2.start()
    # p2.join()
    # p3.start()
    # p3.join()
    foo(1)
    foo(2)
    foo(3)
    end = time.time()   # 直接调用函数时间:6.000343322753906
    print(end - start) #7.214412450790405 不如不开,直接使用串行调用函数反而块
    print('主进程')

优化join

from multiprocessing import Process
import time

def foo(x):
    print(f'进程{x} statr')
    time.sleep(x)
    print(f'进程{x} end')

if __name__ == '__main__':
    start = time.time()
    p_list = []
    for i in range(1,4):
        p = Process(target=foo, args=(i,))
        p.start()
        p_list.append(p)
    print(p_list)
    for p in p_list:
        p.join()
    end = time.time()
    print(end - start) #3.584204912185669
    print('主进程')

process的其它用法

from multiprocessing import Process, current_process
import time,os

def task():
    print('子进程 start')
    print('在子进程中查看自己的pid',current_process().pid) # 在子进程中查看自己的pid
    print('在子进程中查看父进程的pid', os.getppid())
    time.sleep(100)
    print('子进程 end')

if __name__ == '__main__':
    p = Process(target=task)
    p.start()
    print('在主进程查看子进程的pid', p.pid) # 一定要写在 start()之后
    print('主进程的pid', os.getpid())
    print('主进程的父进程Pid', os.getppid())
    print('主进程')

'''
记住这些就OK了  这个是要掌握的
角度  站在当前进程对的角度
os.getpid() #获取当前进程的pid
os.getppid()  获取当前进程的父进程的pid
子进程对象.pid  获取当前进程的子进程pid
'''

process的name和is_alive用法(了解)

'''
迭代:python中可以用for循环使用取值操作过程.
可迭代对象:可以使用for循环遍历的对象,我们称之为可迭代对象.
迭代器:提供数据和记录位置.
生成器:如果函数中有yield我们称之为生成器
'''
# is_alive用法:判断进程是否还活着
# from multiprocessing import Process
# import time
#
# def foo():
#     print('进程 start')
#     time.sleep(2)
#     print('进程 end')
#
# if __name__ == '__main__':
#     p = Process(target=foo)
#     p.start()
#     print(p.is_alive())
#     time.sleep(5)
#     print(p.is_alive())
#     print('主进程')

# Process 的 name 用法
from multiprocessing import Process, current_process
import time

def foo():
    print('进程 start')
    print(current_process().name)# current_process(现在进程的名字)
    time.sleep(2)
    print('进程 end')

if __name__ == '__main__':
    p1 = Process(target=foo)
    p2 = Process(target=foo, name='rocky')
    p1.start()
    print(p1.is_alive()) #True
    p2.start()
    print(p2.is_alive()) #True

    time.sleep(5)
    print(p1.is_alive()) #False
    print(p2.is_alive()) #False

    print('主')

process的terminate用法

from multiprocessing import Process, current_process
import time
def foo():
    print('进程 start')
    time.sleep(20)
    print('进程 end')
if __name__ == '__main__':
    p = Process(target=foo)

    p.start()
    p.terminate() # 给操作系统发送了一个请求,终止子进程
    print(p.is_alive()) # True
    p.join() #阻塞住主进程,等待子进程结束后才会往下运行,所以一旦往下运行了表示子进程已结束
    print(p.is_alive()) #False
    print('主进程')

守护进程

'''
守护进程
守护---》可以理解为伴随的意思
本质也是一个子进程
主进程的代码执行完毕后守护进程就直接结束。但是此时主进程可能没有结束
'''

from multiprocessing import Process
import time

def foo():
    print('守护进程 start')
    time.sleep(5)
    print('守护进程 end')

if __name__ == '__main__':
    p = Process(target=foo)
    p.daemon = True # 表示把这个子进程定义为守护进程  daemon(守护进程)
    p.start()
    time.sleep(2)
    print('主进程')

守护进程2

'''
守护进程
守护--》伴随
本质也是一个子进程
主进程的代码执行完毕守护进程直接结束。
'''

from multiprocessing import Process
import time

def foo():
    print('守护进程 start')
    time.sleep(3)
    print('子进程 end')

def task():
    print('子进程 start')
    time.sleep(5)
    print('子进程 end')

if __name__ == '__main__':
    p = Process(target=foo)
    p1 = Process(target=task)
    p.daemon = True
    p.start()
    p1.start()
    time.sleep(1)
    print('主进程')

抢票小程序

db.txt = {"count": 1}

from multiprocessing import Process
import time
import json
import os

def search():
    time.sleep(1) #模拟网络io
    with open('db.txt', 'rt', encoding='utf-8')as f:
        res = json.load(f)
        print(f'还剩{res["count"]}')

def get():
    with open('db.txt', 'rt', encoding='utf-8')as f:
        res = json.load(f)
    time.sleep(1)  #模拟网络io
    if res['count'] > 0:
        res['count'] -= 1
        with open('db.txt', 'wt', encoding='utf-8')as f:
            json.dump(res,f)
            time.sleep(1.5) #模拟网络io
            print(f'进程{os.getpid()} 抢票成功')
    else:
        print('票已经售空啦!!')

def task():
    search()
    get()

if __name__ == '__main__':
    for i in range(15):
        p = Process(target=task)
        print(p)
        p.start()
        p.join()

#为了保证数据的安全,要牺牲掉效率