Python第三部分进阶6-多进程multiprocessing|进程池Pool|队列Queue

第一部分 进程:

#####################################

1.**多进程**

#####################################

·程序: 是一个指令的集合

  • ·进程: 正在执行的程序;或者说:当你运行一个程序,你就启动了一个进程
        - 编写完的代码,没有运行时,称为程序,正在运行的代码,称为进程
        - 程序是死的(静态的),进程是活的(动态的)
  • ·操作系统轮流让各个任务交替执行,由于CPU的执行速度实在是太快了,我们感觉就像所有任务都在同时执行一样
  • ·多进程中,每个进程中所有数据(包括全局变量)都各有拥有一份,互不影响
  • 变量的修改互相之间不影响:
    在这里插入图片描述

    (1)多进程 实际创建举例:


    在这里插入图片描述(2)进程启动之后 才能查看进程的name 与 pid
    在这里插入图片描述
    多进程举例
from multiprocessing  import  Process
from multiprocessing  import  Pool
from multiprocessing  import  Queue
from multiprocessing  import  Lock
import time

#第一个简单的案例:
def func(name,age):
    for i in range(2):
        print(f"{name}今年{age}岁了")  #简单定义一个函数
        time.sleep(1)


if __name__ == "__main__":
    p1 = Process(target=func, args=("张三", 12), name="第一个进程")  #创建两个小弟。给小弟资源
    p2 = Process(target=func, args=("李四", 18), name="第二个进程")

    p1.start()    #小弟埋头干活
    p2.start()
    print(p1.name, p2.name, p1.pid, p2.pid)   #只有启动之后 才有pid

    p1.join()     #老大等小弟的回复
    p2.join()

要点:

序号说明
1导入包:
from multiprocessing import Process
2第二点——Process() 通过name给进程起个名字:
如果不起名字 默认就是 Proces_1 process_2
3第三点——给函数传递参数、
位置参数用元组形式—— args=(fas,fasf)
如果参数只有一个元素一定要带逗号:
p = Process(target=func , args=(num1,) name=“第一个进程”)
4start() 写到一起,表示多个小弟就绪可以干活了。等CPU的调用
5join() 写在最后,表示等小弟干活结束, 主进程才继续往下走——等小弟活干完了 才往下走,不然一直等进程结束才往下走
在这里插入图片描述
***进程状态说明: 在这里插入图片描述
☆ 带join 主程序等待进程结束后继续再往下走 ;
☆ 如果不带join主程序先执行完不等子进程了

2.重写run()方法- start() 会自动调用(用的不多)

进程对象调用start()方法,默认会调用类中的run()函数执行程序

在这里插入图片描述
#####################################

2.**进程池 Pool()**

#####################################

进程池

1. ·进程池:用来创建多个进程

2. ·当需要创建的子进程数量不多时,可以直接利用multiprocessing中的Process()动态生成多个进程,但如果是上百甚至上千个目标,手动的去创建进程的工作量巨大,此时就可以用到
multiprocessing模块提供的Pool

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

理解进程池:

进程池子大小为3,进程池满了之后 后面的任务进入队列开始排队,有进程执行完,后面队列里的进程就是补充进去。pool.close() 表示不再接收新任务。
在这里插入图片描述

from  multiprocessing  import  Process
from  multiprocessing  import  Pool
import time

def fun1(name):
    s = f"{name}是一个笨鸟,但是只要坚持不懈,肯定可以有所成就,至少可以成为一个合格的程序员"
    print(s)

if __name__ == "__main__":
    po= Pool(3)        ##限制Pool里面能够放置的进程的数量
    for i in range(10):
        po.apply_async(fun1 , ("thomas",))   #添加进程池,直接调用并运行
    po.close()
    po.join()

po.apply_async(fun1 , (“thomas”,)) #添加进程池,直接调用并运行
po.close() #关闭进程池 不再接受新的任务
po.join() #主进程阻塞
在这里插入图片描述

#####################################

3.**多进程之间互相通信(Queue)**

q.put(数据类型不限) ——往队列里加数据
q.get() ——从队列里取数据

#####################################
如下场景: 一个进程负责爬数据,另一个进程负责数据分析,所以需要两个进程之间互相传递数据:
在这里插入图片描述在这里插入图片描述
进程之间数据传递,举例如下图:
在这里插入图片描述在这里插入图片描述

Queue函数:

  1. Queue.qsize() _队列中消息数量 Queue.empty() 队列为空 返回True 否则返回False

  2. Queue.full() 队列满了返回True,队列没满返回Fasle Queue.put(item,[block=,timeout=])

  3. block默认为True,即队列满了阻塞等待腾出空间再放数据,timeout表示等待时间,如果队列一直满的超过timeout时间报Queue.full异常

  4. Queue.get([block=,timeout=]) 获取数据是否设置超时时间
    默认Queue.get(True)
    如果是Queue.get(False)-不阻塞拿不到直接报错

在这里插入图片描述在这里插入图片描述

要点:

(1) Queue —— FiFo——先入先出——最早进去的最早出来

(2) 放置数据与取数据速率不一致;    
   比如往池子里放数据的速率很慢, 取数据的速率很快。 取数据的必然要等待数据    
   再比如放数据的很快, Queue已经阻塞很久,数据还没被取出去。

*** 1.1如何设置等待时间 ?
*** 1.2在等待期间是否可以做点别的任务?

from  multiprocessing import Queue
from multiprocessing import Process
import time

def func1(name,age,q1):   #一级生产商
    for i in range(10):
        q1.put((name ,i),timeout=20)  ##20秒队列还没空间(即退出循环),放置的是一个元组

def func2(q1,q2):    #中间过渡
    while True:
        try:
            k,v = q1.get(timeout=20)   #20秒获取不到数据报错(即退出循环)
            q2.put((k,v))
            print("p2 time is:", time.time())
        except Exception:
            break

def func3(q2):       #最终消费者
    while True:
        try:
            k,v = q2.get(timeout=20)   #20秒获取不到数据报错(即退出循环)
            print("p3获取到的消息是:",k,v)
            print("p3 time is:",time.time())
        except Exception:
            break    #退出循环

if __name__ == "__main__":
    q1 = Queue(100)
    q2 = Queue(20)
    p1 = Process(target=func1, args=("messi", 33, q1))
    p2 = Process(target = func2, args=(q1, q2))
    p3 = Process(target=func3, args=(q2,))

    lst= [p1, p2, p3]
    for i in lst:
        i.start()
    for i in lst:
        i.join()
if __name__ == "__main__":
    q1 = Queue(100)
    q2 = Queue(20)
    p1 = Process(target=func1, args=("messi", 33, q1))
    p2 = Process(target = func2, args=(q1, q2))
    p3 = Process(target=func3, args=(q2,"P3") , name ='111')   #创建两个P3 与 p3_2 进程从队列里面取数据
    p3_2 = Process(target=func3, args=(q2, "P3_2"), name="222")
    lst = [p1,p2,p3,p3_2]
    p1.start()
    p2.start()
    p3.start()
    p3_2.start()

    for i in lst:
        i.join()

#####################################

4.**进程池内进程之间互传数据Manager().Queue()**

q.put(数据类型不限) ——往队列里加数据
q.get() ——从队列里取数据

#####################################

在这里插入图片描述在这里插入图片描述

通过进程池 多个进程之间互相传递数据:

from multiprocessing  import  Process
from multiprocessing  import  Pool
from multiprocessing  import  Queue
from multiprocessing  import  Lock
import time

def func1(name,age,q1):   #一级生产商
    for i in range(10):
        q1.put((name ,i),timeout=20)   #放到队列里面的是一个元组,两个元素
        print("此时队列q1的长度为: ",q1.qsize())
        #time.sleep(1)

def func2(q1):    #从q1 队列里面取值
    while True:
        try:
            k,v = q1.get(timeout=2)        #如果超出2秒 取不到值就报错,退出循环
            print("获取到的k、v是:",k,v)
            time.sleep(1)
        except Exception as e:
            print(e) ;break

if  __name__ == "__main__":
    p = Pool()
    q1 = Manager().Queue()
    #q2 = Manager().Queue()
    p.apply_async(func1, args=("james",19, q1))
    p.apply_async(func2, args=(q1,))

    p.close()
    p.join()
补充知识:

☆☆☆☆☆☆☆☆☆☆重要知识☆☆☆☆☆☆☆☆☆☆

在创建子进程的前面要加上
__name__ == “__main__” (只有windows系统要加) 子进程默认会导入主进程代码(默认执行一遍),所以会导致递归创建子进程

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值