Python多进程

本文介绍了Python的多进程管理,重点关注multiprocessing模块,包括join、Lock、Pipe、Queue、Array和Manager等实现进程间通信的方式。强调了Queue和Pipe在多进程通信中的优势,并详细解释了各种操作如put、get、task_done等方法的使用,同时阐述了进程数据共享的策略,如value、Array和Manager。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Python多进程

  • 多进程就像生产者和消费者的关系一样
  • 比如统计信息:一个负责打开,一个负责处理;或者一个搜索,一个爬
  • 队列:先进先出 例如:queue
    栈:先进后出 例如:网页(打开A里的B里的C,再返回,返回的路径是C到B再到A)

multiprocess

  • multiprocessing包是Python中的多进程管理包,利用multiprocessing.Process对象来创建一个进程。
  • 当某个进程终结之后,需要让主进程等待子进程,调用join()方法
  • multiprocessing提供了Pipe和Queue,效率上更高。应优先考虑Pipe和Queue,避免使用Lock/Event/Semaphore/Condition等同步方式 (因为它们占据的不是用户进程的资源)。
  • 多进程的共享:在多线程中,可以比较容易地共享资源,比如使用全局变量或者传递参数。但在多进程情况下,由于每个进程有自己独立的内存空间,以上方法并不合适。此时我们可以通过Array(进程列表数组共享)和Manager(进程字典列表共享)的方法来共享资源。

join

让主进程等待子进程

import multiprocessing
import os


def info(title):
    print(title)
    print(__name__)
    print('father', os.getppid())
    print('self', os.getpid())
    print('--------')



if __name__ == "__main__": # 除了创建的子进程和子进程调用函数,其他的都是脚本主进程
    # info('hello')
    # 创建一个子进程调用函数
    P = multiprocessing.Process(target=info,args=('hello python',))
    P.start()
    P.join() # 和多线程一样,也是等待的意思
    print('hello word') # 若没有join则会独立运行
"""
结果:
hello python
__mp_main__
father 12500
self 8164
---------
hello word
"""

Lock

  • 进程锁,可有可无(多个进程同时对同一文件处理时可使用)
  • 作用:进程写完出去下个再进来
  • RLock 活动锁
  • Lock 锁不好就会锁死
# 当进程进行文件读写操作的时候(关键性操作的时候)需要使用锁..
from multiprocessing import Process,RLock
import multiprocessing

def _write(str_,lock):
    print(multiprocessing.current_process().name)
    # 写入文件
    path = '/D:/school/python/work/http.txt'

    # with 会自己帮你关掉
    with lock:
                # 路径   模式a:追加  # 编码模式:utf-8, gbk,gb12128
        with open(path, mode='a',encoding='utf8') as f:
            f.write(str_)
    
if __name__ == "__main__":
    ps = []
    # 创建一个活锁
    lock = RLock()
    for i in range(10):
        p = Process(target=_write,args=('今天天气好晴朗\n',lock))
        p.start()
        ps.append(p)
    
    for i in ps:
        i.join()
        

pipe

  • 管道,只能两个管道进行通信(队列可以多个)
import multiprocessing


def func(conn):
    conn.send(['Joker is a good man'])
    print('{} 发送了..'.format(multiprocessing.current_process().name))
    print('{} 接受了 {}'.format(multiprocessing.current_process().name,conn.recv()))
    conn.close()

if __name__ == "__main__":
    conn_a,conn_b = multiprocessing.Pipe()
    p1 = multiprocessing.Process(target=func,args=(conn_a,)).start()
    conn_b.send([1, 2, 3, 4, 5, 6, 7])  # 发送数据给conn_a
    print('main',conn_b.recv())

share

全局变量不共享

    '''
    全局变量不共享
    1809 ['a', 'b', 'c']
    1810 [1, 2, 3]
    '''
  
  # 全局变量不可以进程共享
import multiprocessing
import os
#os:获取进程PID
data = []

def List():
    global data
    data.append(1)
    data.append(2)
    data.append(3)
    print('p',os.getpid(),data)


if __name__ == '__main__':
    p = multiprocessing.Process(target=List,args=()).start()  # 子进程
    data.append('a')  # 脚本主进程
    data.append('b')
    data.append('c')
    print('main',os.getpid(),data)

queue

  • 只能一个一个放(不像pipe)
  • 如果想无穷放,在queue.put()前写 while 1:则循环不止

queueplus

  • queue(maxsize=0)
  • 设置队列的最大长度 如果不定义maxsize则默认maxsize=0也就是无穷大
  • queue.qsize()
    返回队列的大致大小。
    注意,qsize() > 0 不保证后续的 get() 不被阻塞,qsize() < maxsize 也不保证 put() 不被阻塞。
  • queue.empty()
    如果队列为空,返回 True ,否则返回 False 。
    如果 empty() 返回 True ,不保证后续调用的 put() 不被阻塞。
    类似的,如果 empty() 返回 False ,也不保证后续调用的 get() 不被阻塞。
  • queue.full()
    如果队列是满的返回 True ,否则返回 False 。如果 full() 返回 True 不保证后续调用的 get() 不被阻塞。类似的,如果 full() 返回 False 也不保证后续调用的 put() 不被阻塞。
  • queue.put(item,block = True,timeout = None)
    将 item 放入队列。
    如果可选参数 block 是 true 并且 timeout 是 None (默认),则在必要时阻塞至有空闲插槽可用。
    如果 timeout 是个正数,将最多阻塞 timeout 秒,如果在这段时间没有可用的空闲插槽,将引发 Full 异常。
    反之 (block 是 false),如果空闲插槽立即可用,则把 item 放入队列,否则引发 Full 异常 ( 在这种情况下,timeout 将被忽略)。
  • queue_nowait(item)
    相当于put(item.False)
  • queue.get(block=True, timeout=None)
    从队列中移除并返回一个项目。
    如果可选参数 block 是 true 并且 timeout 是 None (默认值),则在必要时阻塞至项目可得到。
    如果 timeout 是个正数,将最多阻塞 timeout 秒,如果在这段时间内项目不能得到,将引发 Empty 异常。
    反之 (block 是 false) , 如果一个项目立即可得到,则返回一个项目,否则引发 Empty 异常 (这种情况下,timeout 将被忽略)。
  • queue.task_done()
    表示前面排队的任务已经被完成。被队列的消费者线程使用。每个 get() 被用于获取一个任务, 后续调用 task_done() 告诉队列,该任务的处理已经完成。
    如果 join() 当前正在阻塞,在所有条目都被处理后,将解除阻塞(意味着每个 put() 进队列的条目的 task_done() 都被收到)。
    如果被调用的次数多于放入队列中的项目数量,将引发 ValueError 异常 。
import multiprocessing
import time
# 一定是要一个放,一个取
# maxsize 设置队列的最大长度.
queue = multiprocessing.Queue(maxsize=10)
def func1(queue):
    while 1:
        print('放入..')
        queue.put(100,timeout=3)

def func2(queue):
    while 1:
        time.sleep(3)
        res = queue.get()
        print(res)

if __name__ == "__main__":
    p1 = multiprocessing.Process(target=func1,args=(queue,))
    # p2 = multiprocessing.Process(target=func2,args=(queue,))

    p1.start()
    # p2.start()
    p1.join()
    # p2.join()

进程数据共享 value

进程列表数组共 Array

  • 一维下可看成列表
# 创建一个共享的列表/数组
# 当你有多个进程需要同时操作某一个数组的时候,你就应该搭建一个共享数组Array.
import multiprocessing

def func(m,i):
    m[i] = 10000
 
def func1():
    # Array 是一个对象
    list_ = multiprocessing.Array('i',[1,2,3])
    return list_


if __name__ == "__main__":
    list_ = func1()
    print(list_[:])
    p1 = multiprocessing.Process(target=func,args=(list_,0))
    p2 = multiprocessing.Process(target=func,args=(list_,1))
    p1.start()
    p2.start()
    p1.join()
    p2.join()
    
                #:代表全取
    print(list_[:])

进程字典列表共享 Manager

import multiprocessing


def func(mydict, mylist):
    mydict["胡旺"] = "牛皮"
    mydict["lalal"] = "大美女"
    mylist.append(11)
    mylist.append(22)
    mylist.append(33)


if __name__ == "__main__":
    # with multiprocessing.Manager() as MG:
    #     mydict=MG.dict()
    #     mylist=MG.list(range(5))
    mydict = multiprocessing.Manager().dict()
                                        # [0,1,2,3,4]
    mylist = multiprocessing.Manager().list(range(5))

    p = multiprocessing.Process(target=func, args=(mydict, mylist))
    p.start()
    p.join()

    print(mylist)
    print(mydict)
# print(list(range(5)))  # 很牛逼的list
共享的有:

pipe queue array manager

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值