我的编程空间,编程开发者的网络收藏夹
学习永远不晚

python并发编程之多进程

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

python并发编程之多进程

  • 一 multiprocessing模块介绍
  • 二 Process类的介绍
  • 三 Process类的使用
  • 四 守护进程

一  multiprocessing模块介绍

 python中的多线程无法利用多核优势,如果想要充分地使用多核CPU的资源(os.cpu_count()查看),在python中大部分情况需要使用多进程。Python提供了multiprocessing。
    multiprocessing模块用来开启子进程,并在子进程中执行我们定制的任务(比如函数),该模块与多线程模块threading的编程接口类似。

  multiprocessing模块的功能众多:支持子进程、通信和共享数据、执行不同形式的同步,提供了Process、Queue、Pipe、Lock等组件。

    需要再次强调的一点是:与线程不同,进程没有任何共享状态,进程修改的数据,改动仅限于该进程内。

二 Process类的介绍

  创建进程的类

Process([group [, target [, name [, args [, kwargs]]]]]),由该类实例化得到的对象,表示一个子进程中的任务(尚未启动)

强调:
1. 需要使用关键字的方式来指定参数
2. args指定的为传给target函数的位置参数,是一个元组形式,必须有逗号

    参数介绍:

1 group参数未使用,值始终为None
2 
3 target表示调用对象,即子进程要执行的任务
4 
5 args表示调用对象的位置参数元组,args=(1,2,'egon',)
6 
7 kwargs表示调用对象的字典,kwargs={'name':'egon','age':18}
8 
9 name为子进程的名称

 方法介绍:

 1 p.start():启动进程,并调用该子进程中的p.run() 
 2 p.run():进程启动时运行的方法,正是它去调用target指定的函数,我们自定义类的类中一定要实现该方法  
 3 
 4 p.terminate():强制终止进程p,不会进行任何清理操作,如果p创建了子进程,该子进程就成了僵尸进程,使用该方法需要特别小心这种情况。如果p还保存了一个锁那么也将不会被释放,进而导致死锁
 5 p.is_alive():如果p仍然运行,返回True
 6 
 7 p.join([timeout]):主线程等待p终止(强调:是主线程处于等的状态,而p是处于运行的状态)。timeout是可选的超时时间,需要强调的是,p.join只能join住start开启的进程,而不能join住run开启的进程  

   属性介绍:

1 p.daemon:默认值为False,如果设为True,代表p为后台运行的守护进程,当p的父进程终止时,p也随之终止,并且设定为True后,p不能创建自己的新进程,必须在p.start()之前设置
2 
3 p.name:进程的名称
4 
5 p.pid:进程的pid
6 
7 p.exitcode:进程在运行时为None、如果为–N,表示被信号N结束(了解即可)
8 
9 p.authkey:进程的身份验证键,默认是由os.urandom()随机生成的32字符的字符串。这个键的用途是为涉及网络连接的底层进程间通信提供安全性,这类连接只有在具有相同的身份验证键时才能成功

三 Process类的使用

注意:在windows中Process()必须放到# if __name__ == '__main__':下

由于Windows没有fork,多处理模块启动一个新的Python进程并导入调用模块。 
如果在导入时调用Process(),那么这将启动无限继承的新进程(或直到机器耗尽资源)。 
这是隐藏对Process()内部调用的原,使用if __name__ == “__main __”,这个if语句中的语句将不会在导入时被调用。
详细介绍

创建并开启子进程的两种方法

#开进程的方法一:
import time
import random
from multiprocessing import Process
def piao(name):
    print('%s piaoing' %name)
    time.sleep(random.randrange(1,5))
    print('%s piao end' %name)



p1=Process(target=piao,args=('egon',)) #必须加,号
p2=Process(target=piao,args=('alex',))
p3=Process(target=piao,args=('wupeqi',))
p4=Process(target=piao,args=('yuanhao',))

p1.start()
p2.start()
p3.start()
p4.start()
print('主线程')
方式一
#开进程的方法二:
import time
import random
from multiprocessing import Process


class Piao(Process):
    def __init__(self,name):
        super().__init__()
        self.name=name
    def run(self):
        print('%s piaoing' %self.name)

        time.sleep(random.randrange(1,5))
        print('%s piao end' %self.name)

p1=Piao('egon')
p2=Piao('alex')
p3=Piao('wupeiqi')
p4=Piao('yuanhao')

p1.start() #start会自动调用run
p2.start()
p3.start()
p4.start()
print('主线程')
方式二

进程直接的内存空间是隔离的

from multiprocessing import Process
n=100 #在windows系统中应该把全局变量定义在if __name__ == '__main__'之上就可以了
def work():
    global n
    n=0
    print('子进程内: ',n)


if __name__ == '__main__':
    p=Process(target=work)
    p.start()
    print('主进程内: ',n)
View Code

Process对象的其他方法或属性

# 进程pid:每一个进程在操作系统内都有一个唯一的id号,称之为pid

# 方法一
'''
from multiprocessing import Process, current_process

import time


def task():
    print('%s is running' % current_process().pid)
    time.sleep(3)
    print('%s is done' % current_process().pid)


if __name__ == '__main__':
    p = Process(target=task)
    p.start()
    print('主进程 ', current_process().pid)
'''

# 方法二
# from multiprocessing import Process
# import os
# import time
#
#
# def task():
#     print('%s is running' % os.getpid())
#     time.sleep(2)
#     print('%s is done' % os.getpid())
#
#
# if __name__ == '__main__':
#     p = Process(target=task)
#     p.start()
#     print('主进程', os.getpid())


from multiprocessing import Process

import os
import time


def task():
    print('%s is running 爹是:%s ' % (os.getpid(), os.getppid()))
    time.sleep(2)
    print('%s is done 爹是:%s ' % (os.getpid(), os.getppid()))

# os.getpid()获得id号;os.getppid())获得父级的id号

if __name__ == '__main__':
    p = Process(target=task)
    p.start()
    p.terminate()   #干死进程
    print(p.is_alive())    #判断是否存活
    print('主进程:%s  主进程他爹:%s' % (os.getpid(), os.getppid()))
View Code

四 守护进程

主进程创建守护进程

  其一:守护进程会在主进程代码执行结束后就终止

  其二:守护进程内无法再开启子进程,否则抛出异常:AssertionError: daemonic processes are not allowed to have children

注意:进程之间是互相独立的,主进程代码运行结束,守护进程随即终止

from multiprocessing import Process

import time


def task(name):
    print('老太监%s活着.....' % name)
    # time.sleep(2)
    # print('皇上正在揍老太监%s...'%name)
    # time.sleep(2)
    # print('老太监%s被揍的嗷嗷叫...' % name)
    # time.sleep(2)
    # print('老太监%s瘫痪在床上痛苦的呻吟...' % name)
    # time.sleep(2)
    # print('不久之后老太监%s就呜呼哀哉了' % name)
    time.sleep(3)
    print('老太监%s正常死亡.....' % name)


if __name__ == '__main__':
    p = Process(target=task, args=('张煜',))
    # p.daemon = True
    p.start()
    time.sleep(1)
    print('皇上:金毛狗正在死....')
    # print('皇上:金毛狗正玩的不亦乐乎')
View Code

 

五 互斥锁

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


# 查票
def search(name):
    with open('db.json', 'rt', encoding='utf_8')as f:
        dic = json.load(f)
    time.sleep(1)
    print('%s 查看到余票为%s' % (name, dic['count']))


# 购票
def get(name):
    with open('db.json', 'rt', encoding='utf_8')as f:
        dic = json.load(f)
    if dic['count'] > 0:
        dic['count'] -= 1
        time.sleep(random.randint(1, 3))
        with open('db.json', 'wt', encoding='utf_8')as f:
            json.dump(dic, f)
            print('%s 购票成功' % name)
    else:
        print('%s 查看到没有余票了' % name)


def task(name, mutex):
    search(name)  # 并发
    mutex.acquire()  # 获取锁
    get(name)  # 串行
    mutex.release()  # 释放锁

    # with mutex:
    #     get(name)


if __name__ == '__main__':
    mutex = Lock()  # 互斥锁
    for i in range(10):
        p = Process(target=task, args=('路人甲%s' % i, mutex))
        p.start()
        # p.join()   # 只能将进程的任务整体变成串行
View Code

 六 队列

进程彼此之间互相隔离,要实现进程间通信(IPC),multiprocessing模块支持两种形式:多列和管道这两种方式都是使用消息传递的

创建队列的类(底层就是一管道和锁定的方式实现的):

1 Queue([maxsize]):创建共享的进程队列,queue是多进程安全的队列,可以使用queue实现多进程之间的数据传递

参数介绍:

maxsize是队列中允许最大项数,省略则无大小限制

方法介绍:

1 q.put方法用以插入数据到队列中,put方法还有两个可选参数:blocked和timeout。如果blocked为True(默认值),并且timeout为正值,该方法会阻塞timeout指定的时间,直到该队列有剩余的空间。如果超时,会抛出Queue.Full异常。如果blocked为False,但该Queue已满,会立即抛出Queue.Full异常。
2 q.get方法可以从队列读取并且删除一个元素。同样,get方法有两个可选参数:blocked和timeout。如果blocked为True(默认值),并且timeout为正值,那么在等待时间内没有取到任何元素,会抛出Queue.Empty异常。如果blocked为False,有两种情况存在,如果Queue有一个值可用,则立即返回该值,否则,如果队列为空,则立即抛出Queue.Empty异常.
3  
4 q.get_nowait():同q.get(False)
5 q.put_nowait():同q.put(False)
6 
7 q.empty():调用此方法时q为空则返回True,该结果不可靠,比如在返回True的过程中,如果队列中又加入了项目。
8 q.full():调用此方法时q已满则返回True,该结果不可靠,比如在返回True的过程中,如果队列中的项目被取走。
9 q.qsize():返回队列中目前项目的正确数量,结果也不可靠,理由同q.empty()和q.full()一样

应用

'''
multiprocessing模块支持进程间通信的两种主要形式:管道和队列
都是基于消息传递实现的,但是队列接口
'''

from multiprocessing import Process,Queue
import time
q=Queue(3)


#put ,get ,put_nowait,get_nowait,full,empty
q.put(3)
q.put(3)
q.put(3)
print(q.full()) #满了

print(q.get())
print(q.get())
print(q.get())
print(q.empty()) #空了
View Code

生产者消费者模型


在并发编程中使用生产者和消费者模式能够解决大多数并发问题。该模式通过平衡生产线程和消费线程的工作 能力来提升程序的整体处理数据的速度。

为什么要使用生产者和消费者模式


在线程的世界里,生产者就是生产数据的线程,消费者就是消费数据的线程。在多线程开发当中,如果生产处理速度很快,而消费者出路速度很慢,那么生产者就必须等待消费者处理完,才能继续生产数据。同样的道理,如果消费者的处理能力大于生产者,那么消费者就必须等待生产者。为了解决这个问题于是引入了生产者和消费者模式。

什么是生产者消费者模式

生产者消费者模式是通过一个容器来解决生产者和消费者的强耦合问题。生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列里取,阻塞队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力。

基于队列实现生产者消费者模型

from multiprocessing import Process,Queue
import time,random,os
def consumer(q):
    while True:
        res=q.get()
        time.sleep(random.randint(1,3))
        print('\033[45m%s 吃 %s\033[0m' %(os.getpid(),res))

def producer(q):
    for i in range(10):
        time.sleep(random.randint(1,3))
        res='包子%s' %i
        q.put(res)
        print('\033[44m%s 生产了 %s\033[0m' %(os.getpid(),res))

if __name__ == '__main__':
    q=Queue()
    #生产者们:即厨师们
    p1=Process(target=producer,args=(q,))

    #消费者们:即吃货们
    c1=Process(target=consumer,args=(q,))

    #开始
    p1.start()
    c1.start()
    print('主')
View Code

 

#生产者消费者模型总结

    #程序中有两类角色
        一类负责生产数据(生产者)
        一类负责处理数据(消费者)
        
    #引入生产者消费者模型为了解决的问题是:
        平衡生产者与消费者之间的工作能力,从而提高程序整体处理数据的速度
        
    #如何实现:
        生产者<-->队列<——>消费者
    #生产者消费者模型实现类程序的解耦和

此时的问题是主进程永远不会结束,原因是:生产者p在生产完后就结束了,但是消费者c在取空了q之后,则一直处于死循环中且卡在q.get()这一步。

解决方式无非是让生产者在生产完毕后,往队列中再发一个结束信号,这样消费者在接收到结束信号后就可以break出死循环

from multiprocessing import Process,Queue
import time,random,os
def consumer(q):
    while True:
        res=q.get()
        if res is None:break #收到结束信号则结束
        time.sleep(random.randint(1,3))
        print('\033[45m%s 吃 %s\033[0m' %(os.getpid(),res))

def producer(q):
    for i in range(10):
        time.sleep(random.randint(1,3))
        res='包子%s' %i
        q.put(res)
        print('\033[44m%s 生产了 %s\033[0m' %(os.getpid(),res))
    q.put(None) #发送结束信号
if __name__ == '__main__':
    q=Queue()
    #生产者们:即厨师们
    p1=Process(target=producer,args=(q,))

    #消费者们:即吃货们
    c1=Process(target=consumer,args=(q,))

    #开始
    p1.start()
    c1.start()
    print('主')
生产者在生产完毕后发送结束信号None

注意:结束信号None,不一定要由生产者发,主进程里同样可以发,但主进程需要等生产者结束后才应该发送该信号

 

其实我们的思路无非是发送结束信号而已,有另外一种队列提供了这种机制

#JoinableQueue([maxsize]):这就像是一个Queue对象,但队列允许项目的使用者通知生成者项目已经被成功处理。通知进程是使用共享的信号和条件变量来实现的。

   #参数介绍:
    maxsize是队列中允许最大项数,省略则无大小限制。    
  #方法介绍:
    JoinableQueue的实例p除了与Queue对象相同的方法之外还具有:
    q.task_done():使用者使用此方法发出信号,表示q.get()的返回项目已经被处理。如果调用此方法的次数大于从队列中删除项目的数量,将引发ValueError异常
    q.join():生产者调用此方法进行阻塞,直到队列中所有的项目均被处理。阻塞将持续到队列中的每个项目均调用q.task_done()方法为止
from multiprocessing import Process, JoinableQueue
import time, random


def producter(name, food, q):
    for i in range(3):
        res = '%s%s' % (food, i)
        time.sleep(random.randint(1, 3))
        q.put(res)
        print('厨师[%s]生产了<%s>' % (name, res))


def consumer(name, q):
    while True:
        res = q.get()
        time.sleep(random.randint(1, 3))
        print('吃货[%s]吃了<%s>' % (name, res))
        q.task_done()


if __name__ == '__main__':
    q = JoinableQueue()
    p1 = Process(target=producter, args=('薛才昌', '泔水', q))
    p2 = Process(target=producter, args=('周迟', '屎包子', q))
    p3 = Process(target=producter, args=('兰天', '牛鞭', q))
    c1 = Process(target=consumer, args=('张煜', q))
    c2 = Process(target=consumer, args=('傻狗', q))
    c1.daemon = True
    c2.daemon = True
    p1.start()
    p2.start()
    p3.start()
    c1.start()
    c2.start()
    p1.join()
    p2.join()
    p3.join()
    q.join() # 主进程等q结束,即q内数据被取干净了

    print('主进程')
View Code

 

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

python并发编程之多进程

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

python并发编程之多进程

阅读目录一 multiprocessing模块介绍二 Process类的介绍三 Process类的使用四 守护进程一  multiprocessing模块介绍 python中的多线程无法利用多核优势,如果想要充分地使用多核CPU的资源(os
2023-01-30

python并发编程之多线程编程

一、threading模块介绍multiprocess模块的完全模仿了threading模块的接口,二者在使用层面,有很大的相似性,因而不再详细介绍二、开启线程的两种方式方式一: from threading import Threa
2023-01-31

python并发执行之多进程

多进程顾名思义程序启动的时候运行多个进程,每个进程启动一条线程进行程序处理。 没启动一个进程就要单独划分一块内存资源。就像工厂的厂房。为了提高效率每多添加一条生产线就要单独再盖一个厂房。每个厂房相互是独立的。所以启动多进程是很消耗资源的,毕
2023-01-31

python并发编程之多进程、多线程、异步和协程详解

最近学习python并发,于是对多进程、多线程、异步和协程做了个总结。 一、多线程多线程就是允许一个进程内存在多个控制权,以便让多个函数同时处于激活状态,从而让多个函数的操作同时运行。即使是单CPU的计算机,也可以通过不停地在不同线程的指令
2022-06-04

Python并发编程之线程池/进程池

原文来自开源中国前言python标准库提供线程和多处理模块来编写相应的多线程/多进程代码,但当项目达到一定规模时,频繁地创建/销毁进程或线程是非常消耗资源的,此时我们必须编写自己的线程池/进程池来交换时间空间。但是从Python3.2开始,
2023-06-02

Python 并发编程-进程

Process类参数介绍group  --------  参数未使用, 值始终为Nonetarget  --------  表示调用对象, 即子进程要执行的任务args  ----------  表示调用对象的位置参数元组, args=(1
2023-01-30

Python并发编程之协程

协程介绍协程:是单线程下的并发,又称微线程,纤程。协程是一种用户态的轻量级线程,即线程是由用户程序自己控制调度的。需要强调的是:#1. python的线程属于内核级别的,即由操作系统控制调度(如单线程遇到io或执行时间过长就会被迫交出cpu
2023-01-30

Python多进程并发(multipro

A manager returned by Manager() will support types list, dict, Namespace, Lock, RLock, Semaphore, BoundedSemaphore, Cond
2023-01-31

Python并发编程:探索多线程和多进程的奥秘

探索Python并发编程的奥秘,掌握多线程与多进程魅力,释放程序性能新高度。 Python、并发编程、多线程、多进程、协程 在计算机科学领域,并发编程一直备受关注,它通过同时执行多个任务来提升程序性能,其中Python作为一门功能丰富的编程语言,也在并发编程方面提供了强大的支持。本文将深入探究Python并发编程,重点阐述多线程和多进程技术的原理与应用,帮助您掌握并发编程技巧,释放程序性能新高度。
Python并发编程:探索多线程和多进程的奥秘
2024-02-05

第36天并发编程之进程篇

目录:  1. 基础概念  2. 创建进程和结束进程  3. 进程之间内存空间物理隔离  4. 进程的属性方法  5. 守护进程  6. 互斥锁  7. IPC通信机制  8. 生产者消费者模型一. 基础概念1. 什么叫做程序,什么叫做进程
2023-01-30

理解Java多线程之并发编程

这篇文章主要介绍了理解Java多线程之并发编程的相关资料,需要的朋友可以参考下
2023-02-02

Python全栈开发之并发编程

No.1 线程什么是多任务就是操作系统可以同时运行多个任务,就是可以一边用浏览器上网,同时又可以听歌,还能再撩个×××姐,这就是多任务,操作系统会轮流把系统调度到每个核心上去执行并发和并行并发是指任务数多余cpu核数,通过操作系统的各种任务
2023-01-31

Python学习之进程和并发

从Python2.4 以后,subprocess模块负责衍生出新的进程,和标准输入,标准输出,标准错误输出交互,并监听返回值。Subprocess模块是用来取代一些老的模块,例如os.system, os.spawn, os.popen和p
2023-01-31

Python 多线程与多进程:进阶指南,解锁并发编程的更多可能性

Python 多线程与多进程是两种重要的并发编程技术,它能够充分利用计算机的处理能力,提高程序的执行效率。本文将深入探讨 Python 多线程和多进程的原理、使用方式以及常见的应用场景,帮助你解锁并发编程的更多可能性。
Python 多线程与多进程:进阶指南,解锁并发编程的更多可能性
2024-02-24

Python CPython 的并发和多线程编程

Python CPython通过多线程和协程实现并发编程,提高应用程序的吞吐量和响应速度。本文将深入探讨Python CPython中的并发和多线程编程技术,并通过代码示例展示其应用。
Python CPython 的并发和多线程编程
2024-03-04

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录