进程Process

进程(Process):拥有自己独立的堆和栈,既不共享堆,也不共享栈,进程由操作系统调度;进程切换需要的资源最大,效率低。

进程的优缺点

进程的优点:

  1. 可以使用计算机多核,进程任务的并行执行,提高执行效率
  2. 运行不受其他进程的影响,创建方便
  3. 空间独立,数据安全

进程的缺点:

  • 进程的创建和删除消耗的系统资源较多

进程的创建方式(方法模式)

Python的标准库提供模块:multiprocessing

进程的创建方式有两种方式:

  1. 方法包装
  2. 类包装
# encoding=utf-8
# 方法包装-多进程实现
from multiprocessing import Process
import os
from time import sleep

def func1(name):
    print("当前进程ID:",os.getpid())
    print("父进程ID:",os.getppid())
    print(f"Process:{name},start")
    sleep(2)
    print(f"Process:{name},end")

if __name__ == '__main__':
    print("当前进程ID:",os.getpid())
    # 创建进程
    p1 = Process(target=func1,args=("p1",))
    p2 = Process(target=func1,args=("p2",))
    p1.start()
    p2.start()


"""
当前进程ID: 9588
当前进程ID: 8004
当前进程ID: 4476
父进程ID: 9588
Process:p1,start
父进程ID: 9588
Process:p2,start
Process:p1,end
Process:p2,end

Process finished with exit code 0
"""

进程的创建方式(继承Process类)

和使用Thread类创建子线程的方式非常类似,使用Process类创建实例化对象,其本质是调用该类的构造方法创建新进程。Process类的构造方法格式:

def __init__(self,group=None,target=None,name=None,args=(),kwargs={})

 group:该参数未进行实现,不需要传参

target:为新建进程指定执行任务,也就是指定一个函数

name:为新建进程设置名称

args:为target参数指定的参数传递非关键字参数

kwargs:为target参数指定的参数传递关键字参数

# 类模式创建进程
from multiprocessing import Process
from time import sleep

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

    def run(self):
        print(f"Process:{self.name},start")
        sleep(3)
        print(f"Process:{self.name},end")

if __name__ == '__main__':
    # 创建进程
    p1 = MyProcess("p1")
    p2 = MyProcess("p2")
    p1.start()
    p2.start()


"""
Process:p1,start
Process:p2,start
Process:p1,end
Process:p2,end

Process finished with exit code 0
"""

Queue实现进程间通信

        实现线程间的通信使用Queue模块中的Queue类,实现进程间的通信需要multiprocessing模块中的Queue类。简单理解Queue实现进程通信的方式就是使用了操作系统给开辟的一个队列空间,各个进程可以把数据放到该队列中,当然也可以从队列中把自己需要的信息取走。

# 使用Queue实现进程间通信的经典代码
from multiprocessing import Process,Queue
from time import sleep

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

    def run(self):
        print("Process:{},start".format(self.name))
        print(f"get Data:{self.mq.get()}")
        sleep(2)
        self.mq.put(f"new_data:{self.name}")
        print(f"Process:{self.name},end")

if __name__ == '__main__':
    # 创建进程列表
    p_list = []
    mq = Queue()
    mq.put("1")
    mq.put("2")
    mq.put("3")
    # 循环创建进程
    for i in range(3):
        p = MyProcess("p{}".format(i),mq)
        p_list.append(p)

    for p in p_list:
        p.start()

    for p in p_list:
        p.join()

    print(mq.get())
    print(mq.get())
    print(mq.get())

"""
Process:p0,start
get Data:1
Process:p2,start
get Data:2
Process:p1,start
get Data:3
Process:p2,endProcess:p1,endProcess:p0,end


new_data:p2
new_data:p1
new_data:p0

Process finished with exit code 0
"""

Pipe实现进程间的通信

         Pipe方法返回conn1、conn2代表一个管道的两端。Pipe方法有duplex参数,如果duplex参数为True(默认值),那么这个参数是全双工模式,也就是说conn1和conn2均可收发。若duplex为False,conn1只负责接收消息,conn2只负责发送消息。send和recv方法分别是发送和接收消息的方法。在全双工模式下,可以调用conn1.send发送消息,conn1.recv接收消息。如果没有消息可接收,recv方法会一致阻塞。如果管道已经被关闭,那么recv方法会抛出EOFError。

#encoding=utf-8
import multiprocessing
from time import sleep

def func1(conn1):
    sub_info = "Hello"
    print(f"进程1{multiprocessing.current_process().pid}发送数据:{sub_info}")
    sleep(1)
    conn1.send(sub_info)
    print(f"来自进程2的:{conn1.recv()}")
    sleep(1)

def func2(conn2):
    sub_info = "你好"
    print(f"进程2{multiprocessing.current_process().pid}发送数据:{sub_info}")
    sleep(1)
    conn2.send(sub_info)
    print(f"来自进程1的:{conn2.recv()}")
    sleep(1)

if __name__ == '__main__':
    # 创建管道
    conn1,conn2 = multiprocessing.Pipe()
    # 创建子进程
    process1 = multiprocessing.Process(target=func1,args=(conn1,))
    process2 = multiprocessing.Process(target=func2,args=(conn2,))
    # 启动子进程
    process1.start()
    process2.start()

"""
进程120024发送数据:Hello
进程26072发送数据:你好
来自进程1的:Hello
来自进程2的:你好

Process finished with exit code 0
"""

Manager管理器实现进程通信

管理器提供了一种创建共享数据的方法,从而可以在不同进程中共享。

# encoding=utf-8
from multiprocessing import Process,current_process
from multiprocessing import Manager

def func(name,m_list,m_dict):
    m_dict['name'] = "Saber"
    m_list.append("你好")

if __name__ == '__main__':
    with Manager() as mgr:
        m_list = mgr.list()
        m_dict = mgr.dict()
        m_list.append("Hello")
        # 两个进程不能直接互相使用对象,需要互相传递
        p1 = Process(target=func,args=("p1",m_list,m_dict))
        p1.start()
        # 等待p1进程结束,主进程继续执行
        p1.join()
        print(f"主进程:{m_list}")
        print(f"主进程:{m_dict}")

"""
主进程:['Hello', '你好']
主进程:{'name': 'Saber'}

Process finished with exit code 0
"""

进程池管理进程的两种典型案例

        Python提供了进程池管理多个进程的方式。进程池可以提供指定数量的进程给客户使用,即当有新的请求提交到进程池中时,如果池未满,则会创建一个新的进程用来执行该请求;如果池中进程数已经达到规定最大值,那么该请求就会等待,只要池中进程空闲下来,该请求就能得到执行。

进程池的优点:

  • 提高效率,节省开辟进程和开辟内存空间的时间,以及销毁进程的时间
  • 节省内存空间
类/方法功能参数
Pool(processes)创建进程池对象processes表示进程池中有多少进程
pool.apply_async(func,args,kwds)异步执行 ;将事件放入到进程池队列func 事件函数 args 以元组形式给func传参kwds 以字典形式给func传参 返回值:返回一个代表进程池事件的对象,通过返回值的get方法可以得到事件函数的返回值
pool.apply(func,args,kwds)同步执行;将事件放入到进程池队列func 事件函数 args 以元组形式给func传参 kwds 以字典形式给func传参
pool.close()关闭进程池
pool.join()回收进程池
pool.map(func,iter)类似于python的map函数,将要做的事件放入进程池func 要执行的函数 iter 迭代对象
# encoding=utf-8
# 进程池使用案例
from multiprocessing import Pool
import os
from time import sleep

def func1(name):
    print(f"当前进程的ID:{os.getpid()},{name}")
    sleep(2)
    return name

def func2(args):
    print(args)

if __name__ == '__main__':
    pool = Pool(5)

    pool.apply_async(func=func1,args=("竹筒饭1",),callback=func2)
    pool.apply_async(func=func1,args=("竹筒饭2",),callback=func2)
    pool.apply_async(func=func1,args=("竹筒饭3",),callback=func2)
    pool.apply_async(func=func1,args=("竹筒饭4",))
    pool.apply_async(func=func1,args=("竹筒饭5",))
    pool.apply_async(func=func1,args=("竹筒饭6",))
    pool.apply_async(func=func1,args=("竹筒饭7",))
    pool.apply_async(func=func1,args=("竹筒饭8",))
    pool.close()
    pool.join()

"""
当前进程的ID:19004,竹筒饭1
当前进程的ID:3888,竹筒饭2
当前进程的ID:7188,竹筒饭3
当前进程的ID:15168,竹筒饭4
当前进程的ID:3548,竹筒饭5
当前进程的ID:3548,竹筒饭6
当前进程的ID:3888,竹筒饭7
当前进程的ID:19004,竹筒饭8
竹筒饭1
竹筒饭2
竹筒饭3

Process finished with exit code 0
"""
# encoding=utf-8
# 使用with管理进程池
from multiprocessing import Pool
import os
from time import sleep

def func1(name):
    print(f"当前进程ID:{os.getpid()},{name}")
    sleep(2)
    return name

if __name__ == '__main__':
    with Pool(5) as pool:
        args = pool.map(func1,("竹筒饭1","竹筒饭2","竹筒饭3","竹筒饭4",
                               "竹筒饭5","竹筒饭6","竹筒饭7","竹筒饭8"))
        for a in args:
            print(a)

"""
当前进程ID:4328,竹筒饭1
当前进程ID:9960,竹筒饭2
当前进程ID:10132,竹筒饭3
当前进程ID:9452,竹筒饭4
当前进程ID:6256,竹筒饭5
当前进程ID:9960,竹筒饭6
当前进程ID:4328,竹筒饭7
当前进程ID:10132,竹筒饭8
竹筒饭1
竹筒饭2
竹筒饭3
竹筒饭4
竹筒饭5
竹筒饭6
竹筒饭7
竹筒饭8

Process finished with exit code 0
"""

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值