一、进程的PID号

  1、作用:一台计算机上面同时会运行很多进程,PID号就是分配给每个进程来用于区分具体是哪个进程的。

  2、终端查看PID号的指令:

    ①windows:tasklist---查看所有进程,tasklist | findstr PID---指定PID号查看具体进程。

    ②linux:ps aux---查看所有进程,ps aux | grep PID---指定PID号查看具体进程。

  3、py程序中查看PID号:

import multiprocessing
import os


def task():
    print('子进程号:{}'.format(os.getpid()))  # 查看当前进程号
    print('子进程号:{}'.format(multiprocessing.current_process().pid))  # 查看当前进程号,效果等同于上一条
    print('主进程号:{}'.format(os.getppid()))  # 查看当前进程的父进程号


if __name__ == '__main__':
    p = multiprocessing.Process(target=task)
    p.start()
    p.join()
    print('主进程号:{}'.format(os.getpid()))
    print('pycharm进程号:{}'.format(os.getppid()))
'''
结果为:
子进程号:12504
子进程号:12504
主进程号:8928
主进程号:8928
pycharm进程号:5888
'''

二、中止进程

import multiprocessing
import time


def task():
    print('子进程开启了...')
    time.sleep(3)
    print('子进程结束了...')


if __name__ == '__main__':
    p = multiprocessing.Process(target=task)
    p.start()
    time.sleep(0.1)
    p.terminate()  # 中止子进程
    time.sleep(0.1)
    print(p.is_alive())  # 判断子进程是否存活
'''
结果为:
子进程开启了...
False
'''

三、僵尸进程与孤儿进程

  1、僵尸进程:子进程被中止的瞬间不会立刻释放所占用的进程号,此时主进程依然可以看到它开设的子进程的一些基本信息,如PID号,运行时间等等,此时的子进程就称为僵尸进程。

  2、孤儿进程:主进程已被中止,但子进程依然存活,此时的子进程就称为孤儿进程,操作系统会开设专门的机制用于管理孤儿进程来回收相关资源。

四、守护进程:伴随主进程的结束而同步中止的子进程就称为守护进程。

import multiprocessing
import time


def task():
    print('子进程开启了...')
    time.sleep(3)
    print('子进程结束了...')


if __name__ == '__main__':
    p = multiprocessing.Process(target=task)
    p.daemon = True  # 声明子进程为守护进程
    p.start()
    time.sleep(0.1)
    print('主进程结束了')
'''
结果为:
子进程开启了...
主进程结束了
'''

 五、互斥锁:多个进程操作同一份数据的时候有可能会出现数据错乱的问题,为了解决这个现象,可以引用互斥锁的机制,但是如此就会把并发的进程转变成为串行,牺牲了效率而保证了数据的安全性和可靠性。

import multiprocessing
import json
import time
import random


def search(x):
    with open(r'E:\python之路\01 课程\week08-day04\03 博客整理\库存.json', 'rt')as f:
        stock_dict = json.load(f)
    print('{}号工作人员正在查询库存为:{}'.format(x, stock_dict.get('stock')))  # 先让用户查看库存


def get_out(x):
    with open(r'E:\python之路\01 课程\week08-day04\03 博客整理\库存.json', 'rt')as f:
        stock_dict = json.load(f)
        stock = stock_dict.get('stock')  # 出库之前确认实际库存
        if stock > 0:  # 若有库存,则出库
            stock -= 1
            stock_dict['stock'] = stock
            with open(r'E:\python之路\01 课程\week08-day04\03 博客整理\库存.json', 'wt')as f:
                json.dump(stock_dict, f)
            print('{}号工作人员已成功出库'.format(x))
        else:  # 若无库存,则显示没有库存,出库
            print('{}号工作人员出库失败,因为没有库存了'.format(x))


def run(x, mutex):  # 给进程对象导入互斥锁参数
    search(x)
    time.sleep(random.uniform(1, 2))  # 模拟网络延迟波动
    mutex.acquire()  # 在执行出库操作前先抢锁,只有抢到锁,才可以进行后续步骤
    get_out(x)
    mutex.release()  # 出库完毕则释放锁


if __name__ == '__main__':
    mutex = multiprocessing.Lock()  # 主进程中生成互斥锁
    for n in range(1, 6):
        p = multiprocessing.Process(target=run, args=(n, mutex))
        p.start()
'''
结果为:
1号工作人员正在查询库存为:1
2号工作人员正在查询库存为:1
3号工作人员正在查询库存为:1
4号工作人员正在查询库存为:1
5号工作人员正在查询库存为:1
3号工作人员已成功出库
5号工作人员出库失败,因为没有库存了
1号工作人员出库失败,因为没有库存了
2号工作人员出库失败,因为没有库存了
4号工作人员出库失败,因为没有库存了
'''

 

六、通信队列:本质就是,管道+互斥锁,遵循“先进先出”的原则。

import multiprocessing

q = multiprocessing.Queue(5)  # 创建一个队列,声明队列最大容量
print(q.empty())  # 判断队列是否为空
q.put('111')
q.put('222')
q.put('333')
q.put('444')
q.put('555')
print(q.full())  # 判断队列是否满载
# q.put('666')  # 当队列满载后若继续加入数据,程序不会报错,会阻塞在原地,直到其他进程取走一个数据,再让本处数据能够顺利加入
v1 = q.get()
v2 = q.get()
v3 = q.get()
v4 = q.get()
v5 = q.get()
# v6 = q.get()  # 当取数据的队列取无可取数据时,程序也不会报错,会阻塞在原地,直到其他进程加入一个数据,再让本处能够顺利取走
# v6 = q.get_nowait()  # 无数据可取则不再阻塞等待,直接报错
# v6 = q.get(timeout=3)  # 无数据可取会等待3秒,之后若依然如此,再报错
try:  # 用 try 语句既可以保证不阻塞,也可以避免报错
    v6 = q.get(timeout=3)  # 或用 v6 = q.get_nowait()
except Exception as e:
    print('队列空了!')

七、IPC机制之生产者消费者模型:借助队列实现进程之间的通信

import multiprocessing
import time
import random


def producer(name, goods, q):
    for n in range(1, 6):
        time.sleep(random.uniform(1, 2))
        in_goods = '{}号产品{}'.format(n, goods)
        q.put(in_goods)
        print('{}生产了{}'.format(name, in_goods))  # 生产者循环产出数据加入队列中


def consumer(name, q):
    while 1:
        time.sleep(random.uniform(1, 2))
        out_goods = q.get()
        print('{}取走了{}'.format(name, out_goods))
        q.task_done()  # 消费者循环从队列取走数据,每取一个,队列的可取值计数器会减1


if __name__ == '__main__':
    q = multiprocessing.JoinableQueue()
    p1 = multiprocessing.Process(target=producer, args=('林师傅', '茶叶蛋', q))
    p2 = multiprocessing.Process(target=producer, args=('刘师傅', '火腿肠', q))
    c1 = multiprocessing.Process(target=consumer, args=('小张', q))
    c2 = multiprocessing.Process(target=consumer, args=('小李', q))
    p1.start()
    p2.start()
    c1.daemon = True
    c2.daemon = True  # 将消费者声明为守护进程,随主程序最后一条代码运行完毕自动终止
    c1.start()
    c2.start()
    p1.join()
    p2.join()  # 等待生产者生产完毕
    q.join()  # 当队列的可取数据为0才会执行到出最后一行代码,也是实现了队列可取数据为0代表程序该结束了,消费者无数据可取,自动消失

 

posted on 2020-05-01 07:01  焚音留香  阅读(117)  评论(0编辑  收藏  举报