Python:多任务,进程的实现,队列的用法,进程池文件复制器实例

一. 进程是指程序在借用或者占用资源时,被称作为进程

实现代码:

import multiprocessing #导入进程模块
import time


def test1():
    while True:
        print("----1----")
        time.sleep(1)


def test2():
    while True:
        print("----2----")
        time.sleep(1)


def main():
 	# 调用进程模块中的Process类,目标设置为某一个函数名,创建进程
    p1 = multiprocessing.Process(target=test1)
    p2 = multiprocessing.Process(target=test2)
    # 执行进程
    p1.start()
    p2.start()


if __name__ == "__main__":
    main()

运行结果:
在这里插入图片描述

`

Linux下查看进程的方式:

ps -aux

在一堆进程的下面找到刚刚运行的进程
在这里插入图片描述

·

进程分析:

主进程创建第一个进程并运行后:
在这里插入图片描述
·

主进程创建第二个进程并运行后:

在这里插入图片描述

·

每次创建一个新的进程都会复制一遍所有的代码和数据占用相当多的资源,所以在所有完成多任务的方法中,进程所占用的资源是最大的

拓展:在操作系统中,如果创建进程并运行后不改变原有的代码则可以共享整篇代码,如果通过特殊手段在新的进程中要更改代码,则会原本原样的拷贝一份完整的代码下来进行修改运行

`

二. 关于进程间的通信(队列的使用)

① socket通信:将资源放到网上,不同的进程通过网络共享同一资源,可以实现在不同电脑中也可以进行进程的通信

② 文件:文件存放于硬盘中,通过对文件的读写操作,实现进程间的通信,但是由于文件在硬盘中,导致效率会较低

③ 队列(Queue):创建一个临时内存空间,以“先进先出,后进后出”的规则完成进程间通信

创建队列:

multiprocessing.Queue() # 返回一个队列对象长度不限,括号中可以填写数字限制队列的长度 

存数据:

q.put() # 当存满队列时,会一直等待队列释放出新的空间
q.put_nowait() # 当存满队列时,会以报错的形式告诉队列空间已满

取数据:

q.get() # 当队列中的数据全部取出后,会一直等待队列中存入新的数据并取出
q.get_nowait() # 当队列中的数据全部取出后,会以报错的形式告诉队列已空

判断队列的空满:

q.full() # 返回True时队列已满
q.empty() # 返回True时队列已空

代码示例:

import multiprocessing

def download_date(q):
    """下载数据"""

    # 假设data为网上下载的数据
    data = [11, 22, 33, 44]
    for i in data:
        q.put(i) # 将数据传到队列中

    print("数据全部传输到队列中")


def handle_date(q):
    """数据处理"""

    date_list = list() # 定义列表存储队列中的数据
    while True:
    # 在不清楚队列中有多少数据时用无限循环取出数据
        date_list.append(q.get()) # 在队列中取出数据存入列表中
        if q.empty():
        # 判断当队列为空时跳出循环
            break
    print(date_list)


def main():
    q = multiprocessing.Queue() #创建队列
    j1 = multiprocessing.Process(target=download_date, args=(q,))
    j2 = multiprocessing.Process(target=handle_date, args=(q,))
    j1.start()
    j2.start()


if __name__ == "__main__":
    main()

注:如果在进程池中用到队列的存取,则需要调用multiprocessing模块中的Manager()类中的Queue()方法,返回一个对象。否则会在进程池中出现异常,但是进程池不会报出异常,导致结果无法达到预期。

·

三. 关于进程池

概念:在开启多进程处理多任务的时候,可以利用Process动态生成多个进程进行处理,但当对处理对象的数目未知或者成百上千时,利用进程池可以提供指定数量的进程供用户循环使用,当有新的请求提交到Pool(进程池)中,如进程池没满,则会创建一个进程执行要求,如果进程池满了,则该请求会等待,直到池中有进程结束后,才会创建进程执行要求。

·

Pool.apply_async(要调用的目标, (传递给目标的参数元组, )) # 将要执行的对象放入进程池中

代码实例:

# -*- coding:utf-8 -*-
from multiprocessing import Pool
import os, time, random


def worker(msg):
    t_start = time.time()
    print("%s开始执行,进程号为%d" % (msg, os.getpid()))
    time.sleep(random.random()*2)
    t_stop = time.time()
    print(msg, "执行完毕,耗时%0.2f" % (t_stop-t_start))

p = multiprocessing.Pool(3) # 定义一个进程池,最大进程数3
for i in range(0, 10):
    # 每次循环将会用空闲出来的子进程去调用目标
    p.apply_async(worker, args=(i,)) # Pool().apply_async(要调用的目标, (传递给目标的参数元组, ))

print("----start----")
p.close() # 关闭进程池,关闭后po不再接收新的请求
p.join() # 等待po进程池中所有进程执行完成后,主线程才继续向下运行
print("----end----")

                     
                          

运行结果:
在这里插入图片描述

·

注:这里上面的进程号只有8037,8038,8039三个进程,都是在进程池中的三个进程

注:如果在进程池中产生了异常,程序并不会报出错误

注:在进程池中使用队列,必须使用multiprocessing模块中Manager()类里的Queue()方法

·

实例:用进程池做出文件复制器

import os
import multiprocessing

def copy_file(q, i, file_names, new_file, file_list):
    """复制文件处理"""

    open_file = open(file_names+"/"+i, "rb") # 按照路径打开文件并赋予以二进制位读取的权限
    content = open_file.read() # 将文件内容保存下来
    open_file.close()
    new_open_file = open(new_file+"/"+i, "wb")
    new_open_file.write(content) # 将文件内容写入
    new_open_file.close()

    # 复制好后向队列中加入文件数据
    q.put(i)



def main():

    # 将当前路径下所有目录保存下来
    current_file = os.listdir(os.getcwd())
    # 获取所要复制的文件夹
    file_names = input("请输入要复制的文件夹:")
    # 判断输入的目录名是否在当前路径中存在
    if file_names in current_file:
        try:
            # 创建新的文件来接收复制,为防止重复创建报错,抓取异常
            new_file = file_names + "[复件]"
            os.mkdir(new_file)
        except:
            pass

        # 得到目录下所有文件并以列表的形式保存
        file_list = os.listdir(file_names)
        # 调用multiprocessing模块中Manager()类里的Queue()方法,返回一个对象,在进程池中使用队列必须使用这种方法
        q = multiprocessing.Manager().Queue()
        # 获取输入的目录里文件的数量
        old_file_num = len(file_list)
        # 创建进程池,可同时进行5个进程
        po = multiprocessing.Pool(5)
        for i in file_list:
            po.apply_async(copy_file, args=(q, i, file_names, new_file, file_list))
        po.close()
        # po.join() ,这里不让主进程等到所有文件都复制好才继续运行
        copy_ok = 0 
        while True:
            # 这里必须要取出数据,否则数据文件一直在队列中导致进程池中的队列是满的,从而出现异常,但是在进程池中不会报出异常
            file_name = q.get()
            # 计数加1
            copy_ok += 1
            # 这里用"\r"使每次输出左对齐,覆盖上一次输出结果
            print("\r完成%.2f %%" % (copy_ok *100 / old_file_num), end="")
            if copy_ok >= old_file_num:
                break


    else:
        print("当前目录下没有该文件")



if __name__ == "__main__":
    main()
    print()
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

此时一位小白路过

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值