进程之间的通信

在python中,当两个进程需要同时工作,相互通信,这时候使用队列可以实现。
python中的队列通过从 multiprocessing中导入 Queue,它是专门在进程中使用的队列

from multiprocessing import Queue
q = Queue(2)
q.put(1)
q.put("D")
print(q.get())
print(q.get())
print(q.empty())

通过put来传入数据,通过get取出。取出完毕可以通过empty进行判断,取出完毕返回True
python中的创建进程需要导入multiprocessing.Process

让我们创建两个进程来测试一下

import multiprocessing
man_data =[]
def download(q):
    lis = [1,2,3]
    for i in lis:
        q.put(i)
    print("添加完毕")
def manage_data(q):
    while True:
        man_data.append(q.get())
        if q.empty():
            break
    print(man_data)
def main():
    # 默认的容量根据内存来定义
    q = multiprocessing.Queue()
    p1 = multiprocessing.Process(target=download, args=(q,))
    p2 = multiprocessing.Process(target=manage_data, args=(q,))
    p1.start()
    p2.start()

if __name__ == '__main__':
    main()

进程池之间的通信

如果需要多个进程,一个一个创建过于麻烦,通过multiprocessing.Poor来创建进程池,初始化Poor时,可以指定最大的进程个数,当进程池没有满,就会创建新的进程来执行该请求,如果进程池满了,那么该请求就会等待,直到池中有进程结束,才会用之前的进程来执行新的任务。
进程池运行的时候,程序是堵塞状态。所以需要用close来关闭进程池,不再接收新的请求

  • apply_async():添加进程任务
  • close():关闭进程池,不再接收新的请求
  • join():优先执行子进程中的任务,主进程最后执行,要在close()的后面

如果在关闭进程池的情况下添加进程任务,会报错

先简单看一下进程池的创建:

import os, time
from multiprocessing import Pool
def worker(msg):
    t_start = time.time()

    print(f"{msg}开始执行,进程号为{os.getpid()}")
    #pid 子进程号  ppid父进程号
    time.sleep(2)

    t_stop = time.time()
    print(msg,f"执行完成,耗时{t_stop-t_start}")

if __name__ == '__main__':
    # 创建进程池
    po = Pool(2)
    for i in range(10):
        po.apply_async(worker, (i,))
    print(123)
    #关闭进程池,不再接收新的请求
    po.close()
    po.join()

进程池之间的通信,通过导入multiprocessing.Manager().Queue()

import multiprocessing
import sys
import traceback
## 进程池通信,使用进程池队列通信

def demo1(q):
    # 进程池里面的程序,如果出现异常,不会主动抛出,而是会阻塞
    try:
        for i in(1,5):
            q.put(i)

    except Exception as e:
        exc_type, exc_value, exc_traceback_obj = sys.exc_info()
        traceback.print_tb(exc_traceback_obj)# 标记出错的位置

def demo2(q):
    print(q.get())

if __name__ == '__main__':
    q = multiprocessing.Manager().Queue()
    po = multiprocessing.Pool()

    po.apply_async(demo1, args=(q,))
    po.apply_async(demo2, args=(q,))
    po.close()
    po.join()

实现多任务文件夹复制

需求1:实现多任务文件夹复制
• 获取用户要复制的文件夹名字
• 创建一个新的文件夹
• 获取文件夹所有待拷贝的文件名字
• 创建进程池
• 添加拷贝任务
需求2:实现进度条

import multiprocessing
import os

def copy_file(file_name,new_fold_name,old_fold_name):
    # 读取文件内容  再保存到新的文件夹中
    with open(old_fold_name + "/" +file_name, "rb") as f:
        content = f.read()

    with open(new_fold_name + "/"+ file_name, "wb") as n_f:
        n_f.write(content)

def main():
    # 获取用户要复制的文件夹名称
    old_fold_name = input("请输入要复制的文件夹名字:")
    #创建新的文件
    new_fold_name = old_fold_name+"附件"
    if not os._exists(new_fold_name):
        os.makedirs(new_fold_name)

    # 获取老文件夹下,所有需要被拷贝文件的名字
    file_names = os.listdir(old_fold_name)

    # 同步 拷贝创建进程池
    po = multiprocessing.Pool()

    for file_name in file_names:
        print(file_name)
        po.apply_async(copy_file, args=(file_name,new_fold_name,old_fold_name))

    po.close()

    # 文件总数
    file_count = len(file_names)
    copy_file_num = 0
    while True:
        copy_file_num+=1
        print("拷贝进度%2.f%%"%(copy_file_num  *100/file_count))

        if copy_file_num >= file_count:
            break

    po.join()


if __name__ == '__main__':
    main()