40章-join方法-进程-生产消费模型-讲师与孤儿进程

章节

  • 创建进程的多种方式
  • join方法
  • 进程间数据默认隔离
  • 进程间通信(IPC机制)
  • 生产者和消费者模型
  • 进程相关方法
  • 守护进程
  • 僵尸进程与孤儿进程
  • 互斥锁

创建进程的多种方式

  • 1.鼠标点击双击运行

  • 2.代码创建

    from multiprocessing import Process
    import time
    
    
    # def task(name):
    #     print(f'{name}正在运行')
    #     time.sleep(3)
    #     print(f'{name}运行结束')
    #
    #
    # if __name__ == '__main__':
    #     p = Process(target=task, args=('jason',))  # 创建一个进程对象
    #     p.start()  # 告诉操作系统创建一个进程(异步操作)
    #     # task('jason')  # 普通的函数调用是同步操作
    #     print('主进程')
    
    -----------------------------------------------------------------------------------
    """
    创建进程的代码在不同的操作系统中 底层原理有区别!!!
    在windows中 创建进程类似于导入模块
        if __name__ == '__main__':  启动脚本
    在mac、linux中 创建进程类似于直接拷贝
        不需要启动脚本 但是为了兼容性 也可以使用
    """
    
    
    class MyProcess(Process):
        def __init__(self, name):
            super().__init__()
            self.name = name
    
        def run(self):
            print(f'{self.name}正在运行')
            time.sleep(5)
            print(f'{self.name}运行结束')
    
    
    if __name__ == '__main__':
        obj = MyProcess('jason')
        obj.start()
        print('主进程')
    

join方法

作用:

join:主进程等待子进程运行结束之后再运行

join实战:

-----------------------------------------------------	
推导步骤2:join方法【合理方式】	很合理!!!
-----------------------------------------------------
from multiprocessing import Process
import time
def task(name,n):
    print(f'{name}正在运行')
    time.sleep(n)
    print(f'{name}运行结束')

if __name__ == '__main__':
    p1 = Process(target=task, args=('jason', 1))  # args就是通过元组的形式给函数传参
    p2 = Process(target=task, args=('kevin', 2))  # 也可以通过kwargs={'name':'jason', 'n':1} 太麻烦 没必要
    p3 = Process(target=task, args=('jerry', 3))
    start_time = time.time()
    p1.start()
    p2.start()
    p3.start()
    p1.join()
    p2.join()
    p3.join()
    end_time = time.time() - start_time
    print('总耗时:%s' % end_time)
    print('主进程')
 ------------执行结果----------------
jason正在运行
kevin正在运行
jerry正在运行
jason运行结束
kevin运行结束
jerry运行结束
总耗时:3.1067492961883545
主进程
  • join注意事项

    一定要看准join的执行位置 以及多任务情况下等待的目标

进程特点:进程间数据默认隔离

多个进程数彼此之间默认是相互隔离的
如果真的想交互,需要借助于'管道'或者'队列'

from multiprocessing import Process

money = 100


def task():
    global money
    money = 666
    print('子进程打印的money', money)


if __name__ == '__main__':
    p = Process(target=task)
    p.start()
    p.join()
    print('父进程打印的money', money)
   
------执行结果---------------
子进程打印的money 666
父进程打印的money 100

进程间通信(IPC机制)

Queue模块

队列,是一个先进先出的容器
方法 作用
.get() 获取队列内容
.put() 往队列中添加
.full() 判断队列是否已存满
.get_nowait() 取出队列数据,无数据取出直接报错
.empty() 判断队列是否已空

Queue实战

  • 实战注意:
q.full()
q.empty()
q.get_nowait()
上述方法在多进程下不能准确使用(失效)!!!
预备知识
	什么是队列:先进先出
	
-------------------------例子----------------------------------
# 1.创建队列对象
from multiprocessing import Queue
q =Queue(3)  #指定只允许存储3条 		    #括号内指定队列可以容纳的数据个数 默认:2147483647
q.put(111)

print(q.full())  #判断是存满
----执行结果-------
False

print(q.get())
----执行结果-------
111

---------如果存入队列4个----------------
q.put(111)
q.put(222)
q.put(333)
q.put(444)  # 超出数据存放极限 那么程序一致处于阻塞态 直到队列中有数据被取出

----------如果连取4个---------------------
print(q.get())  # 超出数据获取极限 那么程序一致处于阻塞态 直到队列中有数据被添加
print(q.get())
print(q.get())
print(q.get())


------------暴躁取值---------------    
print(q.get_nowait())
print(q.get_nowait())
print(q.get_nowait()) 
print(q.get_nowait())  # 队列中如果没有数据可取 直接报错



========================================================================
IPC机制
	1.主进程与子进程通信
 	2.子进程与子进程通信
 
from multiprocessing import Queue, Process
def procedure(q):
    q.put('子进程procedure往队里中添加了数据')

def consumer(q):
    print('子进程的consumer从队列中获取数据', q.get())

if __name__ == '__main__':
    q = Queue()  # 在主进程中产生q对象 确保所有的子进程使用的是相同的q
    p1 = Process(target=procedure, args=(q,))
    p2 = Process(target=consumer, args=(q,))
    p1.start()
    p2.start()
    print('主进程')
    
------------执行结果-----------------
主进程
子进程的consumer从队列中获取数据 子进程procedure往队里中添加了数据    

生产消费者模型

模型 作用
生产者 产生数据
消息队列 数据库/rabitmq/redis/zk/kafka
消费者 处理数据

进程相关方法

方法 作用
.pid 查看pid进程号
os.getpid 查看pid进程号
os.getppid 查看父进程号
.terminate() 销毁子进程
.is_alive() 判断进程是否存活

守护进程

如何理解守护
伴随着守护对象的存活而存活 死亡而死亡

-------------------例子-----------------------------------------------

from multiprocessing import Process
import time


def task(name):
    print('大内总管:%s存活' % name)
    time.sleep(3)
    print('大内总管:%s嗝屁' % name)


if __name__ == '__main__':
    p = Process(target=task, args=('基佬',))
    
    p.daemon = True  # 必须在start之前执行   
    p.start()		# 将子进程设置为守护进程:主进程代码结束 子进程立刻结束
    print('天子Jason寿终正寝!!!')

僵尸进程与孤儿进程

进程
僵尸进程
进程已经运行结束,但是相关的自愿并没有完全清空,需要父进程参与回收
孤儿进程
操作系统领域中,父进程意外终止结束,子进程正常运行,该子进程就称之为孤儿进程,这些孤儿进程,被init进程收养,由init进程对他们完成状态收集工作

互斥锁

--------例子---------------
from multiprocessing import Process
import time
import json
import random


# 查票
def search(name):
    with open(r'data.json', 'r', encoding='utf8') as f:
        data = json.load(f)
    print('%s在查票 当前余票为:%s' % (name, data.get('ticket_num')))


# 买票
def buy(name):
    # 再次确认票
    with open(r'data.json', 'r', encoding='utf8') as f:
        data = json.load(f)
    # 模拟网络延迟
    time.sleep(random.randint(1, 3))
    # 判断是否有票 有就买
    if data.get('ticket_num') > 0:
        data['ticket_num'] -= 1
        with open(r'data.json', 'w', encoding='utf8') as f:
            json.dump(data, f)
        print('%s买票成功' % name)
    else:
        print('%s很倒霉 没有抢到票' % name)


def run(name):
    search(name)
    buy(name)


if __name__ == '__main__':
    for i in range(10):
        p = Process(target=run, args=('用户%s'%i, ))
        p.start()
posted @ 2022-08-09 16:20  名字长的像一只老山羊  阅读(33)  评论(0编辑  收藏  举报