进程

进程

 

  

操作系统的发展史

  """学习并发编程其实就是在学习操作系统的发展史(底层逻辑)"""

 

  1.穿孔卡片时代

    CPU的利用率极低

  2.联机批处理系统

    将多个程序员的程序一次性录入磁带中 之后交由输入机输入并由CPU执行

  3.脱机批处理系统

    现代计算机的雏形(远程输入 高速磁带 主机)

 

多道技术

  # 前提:单核CPU

    多道技术

      切换+保存状态

"""
CPU工作机制
    1.当某个程序进入IO状态的时候 操作系统会自动剥夺该程序的CPU执行权限
    2.当某个程序长时间占用CPU的时候 操作系统也会剥夺该程序的CPU执行权限
"""

 

    并行与并发(******)

      并行:多个程序同时执行

      并发:多个程序只要看起来像同时运行即可

    # 问:单核CPU能否实现并行

      肯定不能,但是可以实现并发

    # 问:12306可以同一时间支持几个亿的用户买票 问是并行还是并发

      肯定是并发(高并发)

 

    星轨:微博能够支持八个星轨

 

进程理论

  # 进程与程序的区别

    程序:一堆代码(死的)

    进程:正在运行的程序(活的)

 

  # 单核情况下的进程调度

    进程调度算法演变

      1.FCFS 先来先服务

        对短作业不友好

      2.短作业优先调度算法

        对长作业不友好

      3.时间片轮转法+多级反馈队列

        先分配给新的多个进程相同的时间片

        之后根据进程消耗的时间片多少分类别......

 

  # 进程三状态(******)

    就绪态 运行态 阻塞态

      进程要想进入运行态必须先经过就绪态

 

  # 同步与异步(******)

    '''用于描述任务的提交方式'''

    同步:提交完任务之后原地等待任务的返回结果 期间不做任何事

    异步:提交完任务之后不原地等待任务的返回结果 直接去做其他事 结果由反馈机制自动提醒

 

  # 阻塞与非阻塞(******)

    '''用于描述任务的执行状态'''

    阻塞:阻塞态

    非阻塞:就绪态 运行态

 

 

创建进程

# 代码层面创建进程

from multiprocessing import Process
import time
import os


def test(name):
    print(os.getpid())  # 获取进程号
    print(os.getppid())  # 获取父进程号
    print('%s正在运行' % name)
    time.sleep(3)
    print('%s已经结束' % name)


if __name__ == '__main__':
    p = Process(target=test, args=('jason',))  # 生成一个进程对象
    p.start()  # 告诉操作系统开设一个新的进程     异步提交
    print(os.getpid())
    print('')


"""
在windows中开设进程类似于导入模块
    从上往下再次执行代码
一定需要在__main__判断语句内执行开设进程的代码

在linux中是直接将代码完整的复制一份执行
    不需要在__main__判断语句内执行
"""


class MyProcess(Process):
    def __init__(self, name):
        super().__init__()
        self.name = name

    def run(self):
        print('%s正在运行' % self.name)
        time.sleep(3)
        print('%s已经结束' % self.name)

if __name__ == '__main__':
    p = MyProcess('jason')
    p.start()
    print('')

 

进程的join方法

from multiprocessing import Process
import time


def test(name, n):
    print('%s is running' % name)
    time.sleep(n)
    print('%s is over' % name)


if __name__ == '__main__':
    p_list = []
    start_time = time.time()
    for i in range(1, 4):
        p = Process(target=test, args=(i, i))
        p.start()
        p_list.append(p)
        # p.join()  # 串行  9s+
    for p in p_list:
        p.join()
    print(time.time() - start_time)

    # p = Process(target=test, args=('jason',))
    # p1 = Process(target=test, args=('kevin',))
    # p2 = Process(target=test, args=('oscar',))
    # p.start()
    # p1.start()
    # p2.start()
    print('主进程')

 

进程间默认无法交互

# 进程间数据是相互隔离的
from multiprocessing import Process

money = 100


def test():
    global money
    money = 999


if __name__ == '__main__':
    p = Process(target=test)
    p.start()
    # 先确保子进程运行完毕了 再打印
    p.join()
    print(money)

 

对象方法

  1.current_process     查看进程号

  2.os.getpid()         查看进程号 os.getppid() 查看父进程进程号

  3.进程的名字,p.name    直接默认就有,也可以在实例化进程对象的时候通过关键字形式传入name=''

  4.p.terminate()      杀死子进程

  5.p.is_alive()         判断进程是否存活 3,4结合看不出结果,因为操作系统需要反应时间。主进程睡0.1即可看出效果

 

僵尸进程与孤儿进程

  僵尸进程

    进程代码运行结束之后并没有直接结束而是需要等待回收子进程资源才能结束

  孤儿进程

    即主进程已经死亡(非正常)但是子进程还在运行

 

守护进程

  守护进程:即守护着某个进程 一旦这个进程结束那么也随之结束

from multiprocessing import Process
import time


def test(name):
    print('总管:%s is running' % name)
    time.sleep(3)
    print('总管:%s is over' % name)


if __name__ == '__main__':
    p = Process(target=test, args=('jason',))
    p.daemon = True  # 设置为守护进程(一定要放在start语句上方)
    p.start()
    print("皇帝jason寿终正寝")
    time.sleep(0.1)

 

 

互斥锁

  问题  :并发情况下操作同一份数据 极其容易造成数据错乱

  解决措施:将并发变成串行 虽然降低了效率但是提升了数据的安全

 

  锁就可以实现将并发变成串行的效果

    行锁、表锁

 

  使用锁的注意事项

    在主进程中产生 交由子进程使用

    1.一定要在需要的地方加锁 千万不要随意加

    2.不要轻易的使用锁(死锁现象)

    # 在以后的编程生涯中 几乎不会解除到自己操作锁的情况

import json
from multiprocessing import Process, Lock
import time
import random


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


# 买票
def buy(name):
    # 先查票
    with open(r'data.txt', 'r', encoding='utf8') as f:
        data_dict = json.load(f)
        ticket_num = data_dict.get('ticket_num')
    # 模拟一个延迟
    time.sleep(random.random())
    # 判断是否有票
    if ticket_num > 0:
        # 将余票减一
        data_dict['ticket_num'] -= 1
        # 重新写入数据库
        with open(r'data.txt', 'w', encoding='utf8') as f:
            json.dump(data_dict, f)
        print('%s: 购买成功' % name)
    else:
        print('不好意思 没有票了!!!')


def run(name,mutex):
    search(name)
    mutex.acquire()  # 抢锁
    buy(name)
    mutex.release()  # 释放锁



if __name__ == '__main__':
    mutex = Lock()
    for i in range(1, 11):
        p = Process(target=run, args=('用户%s' % i,mutex))
        p.start()

 

消息队列

  队列:先进先出

from multiprocessing import Queue


q = Queue(5)  # 括号内可以填写最大等待数

# 存放数据
q.put(111)
q.put(222)
# print(q.full())  # False       判断队列中数据是否满了
q.put(333)
q.put(444)
q.put(555)
# print(q.full())
# q.put(666)  # 超出范围原地等待 直到有空缺位置
# 提取数据
print(q.get())
print(q.get())
print(q.get())
print(q.get())
print(q.get())
# print(q.get())  # 没有数据之后原地等待直到有数据为止
print(q.get_nowait())  # 没有数据立刻报错

"""
full和get_nowait能否用于多进程情况下的精确使用
    不能!!!

队列的使用就可以打破进程间默认无法通信的情况
"""

 

IPC机制

from multiprocessing import Queue, Process


def producer(q):
    q.put("子进程p放的数据")


def consumer(q):
    print('子进程c取的数据',q.get())


if __name__ == '__main__':
    q = Queue()
    p = Process(target=producer, args=(q,))
    c = Process(target=consumer, args=(q,))
    p.start()
    c.start()

    # q.put('主进程放的数据')
    # p = Process(target=consumer, args=(q,))
    # p.start()
    # p.join()
    # print(q.get())
    # print('主')

 

生产者消费者模型

  生产者

    负责产生数据(做包子的)

  消费者

    负责处理数据(吃包子的)

  该模型需要解决恭喜不平衡现象

from multiprocessing import Queue, Process, JoinableQueue
import time
import random


def producer(name, food, q):
    for i in range(10):
        print('%s 生产了 %s' % (name, food))
        q.put(food)
        time.sleep(random.random())


def consumer(name, q):
    while True:
        data = q.get()
        print('%s 吃了 %s' % (name, data))
        q.task_done()


if __name__ == '__main__':
    # q = Queue()
    q = JoinableQueue()
    p1 = Process(target=producer, args=('大厨jason', '玛莎拉', q))
    p2 = Process(target=producer, args=('印度阿三', '飞饼', q))
    p3 = Process(target=producer, args=('泰国阿人', '榴莲', q))
    c1 = Process(target=consumer, args=('班长阿飞', q))

    p1.start()
    p2.start()
    p3.start()
    c1.daemon = True
    c1.start()

    p1.join()
    p2.join()
    p3.join()

    q.join()  # 等待队列中所有的数据被取干净

    print('')

 

END

posted @ 2022-01-13 20:31  Snails蜗牛  阅读(95)  评论(0)    收藏  举报