【操作系统】多进程编程

本文详细介绍了Python中的进程创建,包括使用`fork()`函数和`multiprocessing.Process`类,以及多进程编程的三种方法。同时,讨论了进程间通信的重要性,并通过消息队列展示了如何实现实现进程间的通信。示例代码涵盖了生产者消费者模型的实现。
摘要由CSDN通过智能技术生成

进程的五状态图:
created:进程已经创建,但未被OS接纳为可执行进程。(还没有申请到相应的资源)。

ready:进程做好了准备,准备执行(只等待处理机)。

running:该进程正在执行(单处理机,某一时刻仅一个进程占用处理机)。

waiting:等待某事件发生才能执行,如等待I/O完成。

终止状态.
在这里插入图片描述

1.进程的创建

1.1 fork()函数

linux系统中,用fork()函数

import os
import time

print('当前进程的pid',os.getpid())
print('当前进程的父进程pid',os.getppid())
print('开始创建子进程...')

p = os.fork()
if p==0:
    print('这是子进程返回的,子进程的pid,父进程的pid',os.getpid(),os.getppid())
else:
    print('这是父进程返回的,返回值是子进程的pid,为',p)

执⾏到os.fork()时,操作系统会创建⼀个新的进程复制⽗进程的所有信息到⼦进程中
普通的函数调⽤,调⽤⼀次,返回⼀次,但是fork()调⽤⼀次,返回两次
⽗进程和⼦进程都会从fork()函数中得到⼀个返回值,⼦进程返回是0,⽽⽗进程中返回⼦进程的 id号

1.2 multiprocessing.Process类

Windows没有fork调⽤,由于Python是跨平台的, multiprocessing模块就是跨平台版本的多进程模块。multiprocessing模块提供了⼀个Process类来代表⼀个进程对象。

Process([group [, target [, name [, args [, kwargs]]]]])
target:表示这个进程实例所调⽤对象;
args:表示调⽤对象的位置参数元组;
kwargs:表示调⽤对象的关键字参数字典;
name:为当前进程实例的别名;
group:⼤多数情况下⽤不到;

Process类常⽤⽅法:

is_alive(): 判断进程实例是否还在执⾏; join([timeout]): 是否等待进程实例执⾏结束,或等待多少秒;
start(): 启动进程实例(创建⼦进程); run(): 如果没有给定target参数,对这个对象调⽤start()⽅法时,
就将执 ⾏对象中的run()⽅法; terminate(): 不管任务是否完成,⽴即终⽌;

1.2.1 多进程编程方法1: 实例化对象

p = multiprocessing.Process()

from multiprocessing import Process
import time

def task1():
    print('听音乐')
    time.sleep(1)

def task2():
    print('编程')
    time.sleep(0.5)

# def no_multi():
#     for i in range(2):
#         task1()
#
#     for i in range(5):
#         task2()

def multi():
    processes = []
    for i in range(2):
        p = Process(target=task1,name='音乐任务')
        processes.append(p)
        print(p.name)
        p.start()

    for i in range(5):
        p = Process(target=task2,name='编程任务')
        processes.append(p)
        print(p.name)
        p.start()

    [process.join() for process in processes]   #join方法,等待所有的子进程执行结束,再执行主进程

if __name__ == '__main__':
    start_time = time.time()
    # no_multi()
    multi()
    end_time = time.time()
    print('花费时间:',end_time-start_time)

1.2.2 多进程编程方法2: 创建子类

重写run()方法,函数里面的内容是任务。如果需要传参,在__init__函数中先super继承父类Process,再自定义参数即可。

import time
from multiprocessing import Process

class myProcess(Process):
    """
    创建自己的进程类,父类是Process,重写run方法
    """

    def __init__(self,name):
        """如果任务需要传参,在构造方法里实现
        首先super()继承父类的init,再自定义参数"""
        super(myProcess, self).__init__()
        self.name=name

    def run(self):
        """
        开启进程:p.start()---->相当于p.run()
        重新run方法,内容是要执行的任务
        :return:
        """
        print('listen music,歌曲名称:',self.name)
        time.sleep(1)

if __name__ == '__main__':
    for i in range(10):
        p = myProcess('第%s首歌' %(i+1))
        # p.start()

1.2.3 多进程编程方法3:进程池

为什么需要进程池:
当被操作对象数目不大时,可以直接利用multiprocessing中的Process动态成生多个进程,十几个还好,但如果是上百个,上千个目标,手动的去限制进程数量却又太过繁琐,此时可以发挥进程池的功效。

Pool可以提供指定数量的进程供用户调用,当有新的请求提交到pool中时,如果池还没有满,那么就会创建一个新的进程用来执行该请求;但如果池中的进程数已经达到规定最大值,那么该请求就会等待,直到池中有进程结束,才会创建新的进程来它。
在这里插入图片描述

from multiprocessing import Process, Pool
import time
def is_prime(num):
    if num == 1:
        return False

    for i in range(2,num):
        if num%i == 0:
            return False
        else:
            return True

def task(num):
    if is_prime(num):
        print('%s是素数'%(num))

def multi(start,end):
    processes = []
    for num in range(start,end+1):
        p = Process(target=task,args=(num,))
        p.start()
        processes.append(p)
    [process.join() for process in processes]

def no_multi(start,end):
    for i in range(start,end):
        task(i)

def use_pool():
    """使用进程池"""
    p = Pool(multiprocessing.cpu_count())
    p.map(task,list(range(1,500000)))
    p.close()  #关闭进程池
    p.join()   #阻塞,等待所有的子进程执行结束,再执行主进程


if __name__ == '__main__':
    start_time = time.time()
    # multi(1,4000) #7.436190128326416
    # no_multi(1,500000)  #1.3182339668273926
    use_pool()   #0.9440164566040039
    end_time = time.time()
    print('所用时长',end_time-start_time)

2.进程间通信

2.1 通信目的

在这里插入图片描述

2.2 通信方式

在这里插入图片描述

2.2.1 消息队列

可以使⽤multiprocessing模块的Queue实现多进程之间的数据传递,Queue 本身是⼀个消息列队程序。

Queue.qsize(): 返回当前队列包含的消息数量;
Queue.empty(): 如果队列为空,返回True,反之False ;
Queue.full(): 如果队列满了,返回True,反之False;
Queue.get([block[, timeout]]):
获取队列中的⼀条消息,然后将其从列队中移除,block默认值为True;
Queue.get_nowait():
相当Queue.get(False);
Queue.put(item,[block[, timeout]]):
将item消息写⼊队列,block默认值 为True;
Queue.put_nowait(item):
相当Queue.put(item, False)

创建子类的方式 实现消息队列的通信方式

# 生产者消费者模型)   用继承Process类的方式,实现消息队列的通信方式
from multiprocessing import Process,Queue
import time

class Producer(Process):
    def __init__(self,queue):
        super(Producer, self).__init__()
        self.queue = queue

    def run(self):
        #将需要通信的数据写入队列中
        for i in range(10):
            self.queue.put(i)
            time.sleep(0.5)
            print('传递消息,内容为%s' %(i))

class Consumer(Process):
    def __init__(self,queue):
        super(Consumer, self).__init__()
        self.queue = queue


    def run(self):
        while True:
            time.sleep(0.5)
            recvData = self.queue.get()
            print('接收到另一进程传递的数据:%s' %(recvData))


if __name__ == '__main__':
    q = Queue()
    p1 = Producer(q)
    p2 = Consumer(q)

    p1.start()
    p2.start()

    p1.join()
    p2.join()
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值