进程

2. 进程

[TOC]

程序和进程

'''
1. 程序:一堆代码
2. 进程:进程是系统进行资源分配和调度的基本单位,相当于车间
  - 每个进程会自带一个主线程,可以开启多个线程
  - 开启进程的开销远大于线程
    开启进程时会开辟一个名称空间,每开辟一个进程都会占用一份内存资源
  - 可以实现并行
'''

进程调度

'''
1. 先来先服务调度算法(FCFS)
  - 根据先后顺序调度,适用于长作业和CPU密集型作业

2. 短作业优先调度算法(SJ/PF)
  - 根据用时长短调度,

3. 时间片轮转法(RR)
  - 将CPU的处理时间分成固定大小的时间片,在规定时间片内没有执行完,就会释放CPU占用,排到就绪末尾等待下一次调度

4. 多级反馈队列
  - 设置多个就绪队列,就绪队列的优先级依次降低
  - 就绪队列优先级越高,规定时间片就越小
  - 当就绪队列的规定时间片没有执行完时,会放到下一队列的末尾
  注意:仅当第一队列空闲时,才会才调度第二队列中的进程运行;
     当优先级高的队列进入新进程时,会优先执行新进程,并将当前进程放置当前队列的末尾,
'''

阻塞和非阻塞

'''
1. 状态介绍
  - 就绪态:所有进程创建时都会进入就绪态,准备调度
  - 运行态:调度后的进程进入运行态
  - 阻塞态:凡是遇到IO操作的进程都会进入阻塞态,若IO结束则重新进入就绪态

2. 阻塞和非阻塞
  - 阻塞:阻塞态
  - 非阻塞:就绪态和运行态
'''

同步和异步

'''
1. 同步
  - 一个任务的完成需要依赖另外一个任务时,只有等待被依赖的任务完成后,依赖的任务才能算完成

2. 异步
  - 不需要等待被依赖的任务完成,只是通知被依赖的任务要完成什么工作,依赖的任务也立即执行,只要自己完成了整个任务就算完成了。至于被依赖的任务

注意
  1. 同步异步是指执行任务的方式  
  2. 阻塞非阻塞是指采取某种执行任务方式后的状态,同步的执行任务就会造成阻塞
'''

串行、并行和并发

'''
1.串行:
  - 多个任务时,各个任务按顺序执行,完成一个之后才能进行下一个

2. 并行
  - 真正的两者同时执行
  - 要具备多个cpu才能并行

3. 并发
  - 看上去是同时在执行,实际上是不停在保存状态+切换
  - 当执行任务阻塞时就切换执行下一个任务,从而提高效率

注意:同步异步是要求任务之间是否有依赖关系,串行并行不需要依赖关系
'''

创建进程的方式

from multiprocessing import Process

# 1. 方式1
# 定义一个任务
def task(name):
    print(f'{name}执行了')

if __name__ == '__main__':
    # target为任务名,args用来传参,必须是元组,加逗号
    p = Process(target=task,args=('wick',))
    p.start()


# 2. 方式2
# 定义一个类,类中的函数必须是run
class MyProcess(Process):
    def __init__(self,name):
        super().__init__()
        self.name=name

    def run(self):
        print(f'{self.name}执行了')

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


'''
注意:
  - 在window系统下,创建子进程,windows会把父进程代码重新加载一次
  - 因此需要使用if __name ==‘__main’判断创建子进程,否则会陷入递归
'''   

进程对象的方法

join方法和守护进程

'''
1. join方法
  - 子进程结束后再结束父进程
  -  必须用在p.start()后
  - 只能join住start开启的进程,而不能join住run开启的进程 

2. 守护进程
  - 主进程结束后,产生的所有子进程也会跟着结束
  - 守护进程内无法再开启子进程
  - 必须用在p.start()前
'''
from multiprocessing import Process

def task(name):
    print(f'{name}的任务已经结束')

if __name__ == '__main__':
    p = Process(target = task,args = ('json',))
    p.daemon = True # 主进程结束,子进程也结束
    p.start()  
    p.join()  # 主进程等子进程执行完再结束
    print('主进程')

僵尸进程与孤儿进程

'''
1. 僵尸进程
  - 子进程已经结束,但是pid号还存在,没有销毁,会占用pid号,占用操作系统资源
2. 孤儿进程
  - 子进程还在执行,但父进程意外结束
  - 操作系统优化机制:会回收孤儿进程  
'''

其他方法

'''
1. current_process().pid:获取子进程号
2. p.terminate():终止子进程
3. p.is_alive():判断子进程是否存活
4. os.getppid():获取主主进程号
5. os.getppid():获取主主进程号
'''
from multiprocessing import Process
from multiprocessing import current_process
import os
import time

def task(name):
    # 1. current_process().pid:获取子进程号
    print(f'{name}开始执行任务',current_process().pid)

if __name__ == '__main__':
    p = Process(target = task,args = ('json',))
    p.start() 
    p.join()  
    # 2. p.terminate():终止子进程
    p.terminate()
    time.sleep(0.1)  # 主进程进入阻塞态,子进程进入运行态

    # 3. p.is_alive():判断子进程是否存活
    print(p.is_alive())

    # 4. os.getppid():获取主主进程号
    print('主进程',os.getpid())  

    # 5. os.getppid():获取主主进程号
    print('主主进程',os.getppid())

进程互斥锁

'''
1. 进程互斥锁
  - 进程之间数据不共享,但是共享同一套文件系统,当并发或并行修改文件时,就会发生错误
  - 互斥锁:让并发变成串行,牺牲了执行效率,保证了数据安全

2. mutex = Lock()
  - mutex.acquire() 加锁
  - mutex.release() 释放锁
'''
# 模拟抢票功能.py
import json
import time
from multiprocessing import Process
from multiprocessing import Lock


# 查看余票
def search(user):
    with open('data', 'r', encoding='utf-8')as f:
        dic = json.load(f)
    print(f'{user}查看余票:{dic.get("ticket")}')


def buy(user):
    with open('data', 'r', encoding='utf-8')as f:
        dic = json.load(f)

     # 模拟网络延迟
    time.sleep(1)

    if dic.get("ticket") > 0:
        dic['ticket'] -= 1
        with open('data', 'w', encoding='utf-8')as f:
            json.dump(dic, f)
        print(f'{user}抢票成功')
    else:
        print(f'{user}抢票失败')


def run(user, mutex):
    search(user)

    # 加锁
    mutex.acquire()
    buy(user)
    # 释放锁
    mutex.release()


if __name__ == '__main__':
    with open('data', 'w', encoding='utf-8')as f:
        json.dump({"ticket":1}, f)

    mutex = Lock()

    for i in range(10):
        p = Process(target=run, args=(f'用户{i}',mutex))
        p.start()

进程间的通信

进程间数据隔离

from multiprocessing import Process

x = 100

def func():
    global x
    x = 200

if __name__ == '__main__':
    p = Process(target = func)
    p.start()
    print(x)  # 100
    print('主进程')

队列(Queue)

'''
1. 队列
  - 相当于内存中的一个队列空间,可以存放多个数据,遵循‘先进先出’(管道+锁)

2. 堆栈
  - 遵循先进后出
'''

from multprocessing import Queue
q = Queue(3)  # 参数代表队列中存放的参数数量,默认无限大

# 1. put:添加数据,超过数量限制就会卡在那里
q.put(1)

# 2. put_nowait:添加数据,超过数量限制就报错
q.put_nowait(2)  

# 3. get:获取数据,先进先出,没有会卡住
print(q.get())  # 1

# 4. get_nowait:获取数据,没有则报错
print(q.get_nowait())  # 2

# 5. full:判断队列是否满了
print(q.full())

# 6. empty:判断队列是否为空
print(q.empty:()) 

进程间通信(IPC)

进程间数据是相互隔离的,若想实现进程间通信,可以利用队列

from multiprocessing import Process
from multiprocessing import Queue

def put(q):
    data = '数据'
    q.put(data)
    print('进程1添加数据到队列中')

def get(q):
    data = q.get()
    print(f'进程1从队列获取数据{data}')

if __name__ == '__main__':
  q = Queue()
    p1 = Process(target=put, args=(q,))
  p2  = Process(target=get, args=(q,))

    p1.start()
    p2.start()

生产者和消费者模型

'''
1. 什么是生产者和消费者模型
  - 生产者消费者模式是通过一个≥容器来解决生产者和消费者的强耦合问题
  - 生产者与消费者利用阻塞队列来进行通讯,生产者生成数据后直接丢给阻塞队列,消费者需要数据则从阻塞队列获取,

2. 优势
  - 解耦
    生产者和消费者依赖于某个缓冲区,两者之间不直接依赖,耦合度低
  - 支持并发
  - 支持忙闲不均
    生产者和消费者处理速率不同时,因为有缓冲区,不会总体处理效率

3. 应用场景
  - 应用于解决生产者与消费者的生产与消费的速率不一致的问题,比如用户提交订单场景
'''
from multiprocessing import Queue,Process
import time

# 生产者
def producer(food,q):
    for i in range(9):
        data = (food,i)
        print(f'生产了{data}')
        q.put(data)
        time.sleep(1)

# 消费者
def consumer(q):
    while True:
        data = q.get()
        if not data:
            break
        print(f'吃了{data}')

if __name__ == '__main__':
    q= Queue()

    p1 = Process(target=producer, args=('yox',q,))

    c1 = Process(target=consumer, args=(q,))

    p1.start()
    c1.start()

    p1.join()  # p1进程执行完后再结束主进程
    print('主进程结束')

posted on 2025-12-05 11:21  wickyo  阅读(0)  评论(0)    收藏  举报