广告
返回顶部
首页 > 资讯 > 后端开发 > Python >python并发编程之多进程
  • 853
分享到

python并发编程之多进程

之多进程python 2023-01-30 22:01:36 853人浏览 薄情痞子

Python 官方文档:入门教程 => 点击学习

摘要

阅读目录 一 multiprocessing模块介绍 二 Process类的介绍 三 Process类的使用 四 守护进程 一  multiprocessing模块介绍  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

 

--结束END--

本文标题: python并发编程之多进程

本文链接: https://www.lsjlt.com/news/179480.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

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

下载Word文档
猜你喜欢
  • python并发编程之多进程
    阅读目录 一 multiprocessing模块介绍 二 Process类的介绍 三 Process类的使用 四 守护进程 一  multiprocessing模块介绍  python中的多线程无法利用多核优势,如果想...
    99+
    2023-01-30
    之多 进程 python
  • python并发编程之多线程编程
    一、threading模块介绍 multiprocess模块的完全模仿了threading模块的接口,二者在使用层面,有很大的相似性,因而不再详细介绍 二、开启线程的两种方式 方式一: from threading import ...
    99+
    2023-01-31
    之多 线程 python
  • python并发执行之多进程
        多进程顾名思义程序启动的时候运行多个进程,每个进程启动一条线程进行程序处理。 没启动一个进程就要单独划分一块内存资源。就像工厂的厂房。为了提高效率每多添加一条生产线就要单独再盖一个厂房。每个厂房相互是独立的。所以启动多进程是很消耗资...
    99+
    2023-01-31
    之多 进程 python
  • python并发编程之多进程、多线程、异步和协程详解
    最近学习python并发,于是对多进程、多线程、异步和协程做了个总结。 一、多线程 多线程就是允许一个进程内存在多个控制权,以便让多个函数同时处于激活状态,从而让多个函数的操作同时运行。即使是单CPU的计...
    99+
    2022-06-04
    之多 多线程 详解
  • Python并发编程之线程池/进程池
    原文来自开源中国前言python标准库提供线程和多处理模块来编写相应的多线程/多进程代码,但当项目达到一定规模时,频繁地创建/销毁进程或线程是非常消耗资源的,此时我们必须编写自己的线程池/进程池来交换时间空间。但是从Python3.2开始,...
    99+
    2023-06-02
  • Python并发编程之协程
    协程介绍 协程:是单线程下的并发,又称微线程,纤程。协程是一种用户态的轻量级线程,即线程是由用户程序自己控制调度的。 需要强调的是: #1. python的线程属于内核级别的,即由操作系统控制调度(如单线程遇到io或执行时间过长就会被迫...
    99+
    2023-01-30
    Python
  • Python 并发编程-进程
    Process类参数介绍 group  --------  参数未使用, 值始终为None target  --------  表示调用对象, 即子进程要执行的任务 args  ----------  表示调用对象的位置参数元组, arg...
    99+
    2023-01-30
    进程 Python
  • 理解Java多线程之并发编程
    目录1 多线程的使用场景2 多线程的缺点2.1 上下文切换的开销(1)上下文切换的开销(2)如何减少上下文切换2.2 多线程中的数据一致性问题(1)线程中访问外部数据的过程(2)线程...
    99+
    2023-02-02
    Java并发编程 java并发编程实战 java并发编程的艺术
  • Python多进程并发(multipro
     A manager returned by Manager() will support types list, dict, Namespace, Lock, RLock, Semaphore, BoundedSemaphore, Con...
    99+
    2023-01-31
    进程 Python multipro
  • Python全栈开发之并发编程
    No.1 线程 什么是多任务 就是操作系统可以同时运行多个任务,就是可以一边用浏览器上网,同时又可以听歌,还能再撩个×××姐,这就是多任务,操作系统会轮流把系统调度到每个核心上去执行 并发和并行 并发是指任务数多余cpu核数,通过操作系统的...
    99+
    2023-01-31
    Python
  • python 并发执行之多线程
        正常情况下,我们在启动一个程序的时候。这个程序会先启动一个进程,启动之后这个进程会拉起来一个线程。这个线程再去处理事务。也就是说真正干活的是线程,进程这玩意只负责向系统要内存,要资源但是进程自己是不干活的。默认情况下只有一个进程只会...
    99+
    2023-01-31
    之多 线程 python
  • 第36天并发编程之进程篇
    目录:   1. 基础概念   2. 创建进程和结束进程   3. 进程之间内存空间物理隔离   4. 进程的属性方法   5. 守护进程   6. 互斥锁   7. IPC通信机制   8. 生产者消费者模型 一. 基础概念 1. 什...
    99+
    2023-01-30
    进程
  • python基础之并发编程(一)
    目录一、进程(Process)二、线程(Thread)三、并发编程解决方案:四、多线程实现 (两种)1、第一种 函数方法2、第二种 类方法包装五、守护线程与子线程1、线程在分法有:2...
    99+
    2022-11-12
  • python基础之并发编程(二)
    目录一、多进程的实现方法一方法二:二、使用进程的优缺点1、优点2、缺点三、进程的通信1、Queue 实现进程间通信2、Pipe 实现进程间通信(一边发送send(obj),一边接收(...
    99+
    2022-11-12
  • python基础之并发编程(三)
    目录一、协程定义和作用1、使用协程的优点2、使用协程的缺点二、Greenlet 的使用三、Gevent的使用四、async io 异步 IO1、asyncio中的task的使用五、总...
    99+
    2022-11-12
  • Python并发编程之IO模型
    五种IO模型 为了更好地了解IO模型,我们需要事先回顾下:同步、异步、阻塞、非阻塞 同步(synchronous) IO异步(asynchronous) IO阻塞(blocking)...
    99+
    2022-11-13
  • Python并发编程多进程,多线程及GIL全局解释器锁
    目录1. 并发与并行2. 线程与进程的应用场景2.1. 并行/并发编程相关的技术栈3. Python中的GIL是什么,它影响什么1. 并发与并行 所谓的并行(Parallelism)...
    99+
    2022-11-11
  • Python学习之进程和并发
    从Python2.4 以后,subprocess模块负责衍生出新的进程,和标准输入,标准输出,标准错误输出交互,并监听返回值。Subprocess模块是用来取代一些老的模块,例如os.system, os.spawn, os.popen和p...
    99+
    2023-01-31
    进程 Python
  • Java并发编程进阶之线程控制篇
    目录一、线程的基本概念1.并行和并发2.进程和线程二、线程的运行状态三、线程操作实践1.线程两种定义方法2.启动线程3.同时定义和启动线程4.线程弹出与暂停5.线程等待与唤醒6.线程...
    99+
    2022-11-13
  • Python 并发编程到底有多难?
    Python 是一种简单易学的编程语言,但是在处理大量数据、网络请求等任务时,单线程执行效率往往较低。因此,Python 并发编程成为了一个热门话题。那么,Python 并发编程到底有多难呢? 在 Python 中,实现并发编程有多种方式...
    99+
    2023-08-08
    并发 apache django
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作