个人笔记——多任务之进程

进程

进程即运行中的程序,进程拥有资源,可以让操作系统调动资源
一个程序可以开启多个进程

进程的状态

1.就绪态:运行的条件都已经满足,正在等待系统执行
2.执行态:cpu正在执行其功能
3.等待态:等待某些条件满足,例如一个程序sleep了,此时就处于等待态

进程的创建

每一个进程的创建都相当于将主进程的资源包括内存再复制一份(代码只有一份,是共享的,只不过主进程和分进程负责的内容不同),然后再运行,线程则都是共享,所以相比于线程,进程消耗的资源比较多
使用multiprocessing模块
例:

import multiprocessing
import time


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


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


def main():
    p1 = multiprocessing.Process(target=test1)
    p2 = multiprocessing.Process(target=test2)
    p1.start()
    p2.start()


if __name__ == "__main__":
    main()

进程和线程对比

进程:能够完成多任务,比如在一台电脑上能运行多个QQ
线程:能够完成多任务,比如一个QQ中的多个聊天窗口,比较轻量级
先有进程才有线程,实质上进程只是一个资源分配的单位,线程是操作系统调度单位,去运行,一个程序中至少有一个主线程。多线程的多任务是在一份资源里面多箭头实现,多进程多任务是复制多份资源多箭头来实现。
线程相当于一个工作台上有多个工人,进程相当于多个工作台。线程执行开销小,但不利于资源的管理和保护,进程正相反

进程间的通信——Queue

可以使用multiprocessing模块的Queue实现多进程之间的数据传递,Queue本身是一个消息列队程序
例1:Queue的常用方法

import multiprocessing
q = multiprocessing.Queue(3)  # 放3个消息
q.put('111')
q.full()  # 判断是否放满 返回False
q.put(2222)
q.put([5, 6, 88, 96])
q.full()  # 判断是否放满 返回True 
'''此时如果继续put,则程序会堵塞在此处'''
q.get()  # '111' 取出,先放进的先取出
q.get()  # 2222
q.get()  # 列表取出来
'''此时如果继续get,则程序会堵塞在此处'''
q.empty()  # 判断是否为空,返回True

例2:进程之间传递数据

import multiprocessing


def download_from_web(q):
    '''下载数据'''
    # 模拟从网上下载的数据
    data = [11, 55, 88, 99]

    # 向队列中写入数据
    for temp in data:
        q.put(temp)
    print("---下载器已经下载数据并存入队列---")


def analysis_data(q):
    '''数据处理'''
    waitting_analysis_data = list()  # 和[]等效,更直观一些
    # 从队列中获取数据
    while True:
        data = q.get()
        waitting_analysis_data.append(data)
        if q.empty():
            break
    print(waitting_analysis_data)


def main():
    # 1.创建一个队列
    q = multiprocessing.Queue()  # 不填写参数默认最大
    # 2.创建多个进程,将队列的引用当做实参进行传递
    p1 = multiprocessing.Process(target=download_from_web, args=(q,))
    p2 = multiprocessing.Process(target=analysis_data, args=(q,))
    p1.start()
    p2.start()

进程池

当需要创建的子进程不多时,可以直接使用multiprocessing中的Process动态生成多个进程,但如果是上百甚至上千个目标,手动创建进程工作量巨大,此时就可以使用multiprocessing模块提供的Pool方法
初始化Pool时,可以指定一个最大进程数,当有新的请求提交到Pool时,如果池还没满,那么就会创建一个新的进程用来执行该请求,如果池中进程数已经到达最大值,则该请求会等待,直至池中有进程结束,才会用之前的进程来执行新任务
例:

import multiprocessing
import time
import os
import random


def worker(msg):
    t_start = time.time()
    print("%s开始执行,进程号为%d" % (msg, os.getpid()))
    # random.random()随机生成0~1之间的浮点数
    time.sleep(random.random()*2)
    t_stop = time.time()
    print("%s执行完毕,耗时%.02f" % (msg, t_stop-t_start))


def main():
    po = multiprocessing.Pool(3)  # 定义一个进程池,最大进程数为3
    for i in range(10):
        # Pool().apply_async(要调用的目标,(传递给目标的参数元组,))
        # 每次循环将会用空闲出来的子进程去调用目标
        po.apply_async(worker, (i,))
    po.close()  # 关闭进程池
    po.join()  # 等待po中所有的子进程执行完,必须放在close语句后面
    """如果不添加join,则随着主进程结束,进程池内的程序也不再运行"""


if __name__ == "__main__":
    print("-----start-----")
    main()
    print("-----end-----")

案例:文件夹copy器

import multiprocessing
import os


def copy_file(q, file_name, old_folder_name, new_folder_name):
    """完成文件复制"""
    # print("正在copy文件:从%s拷贝至%s,文件名:%s" % (old_folder_name, new_folder_name, file_name))
    old_f = open(old_folder_name + "/" + file_name, "rb")
    content = old_f.read()
    old_f.close()

    new_f = open(new_folder_name + "/" + file_name, "wb")
    new_f.write(content)
    new_f.close()

    # 如果copy完了文件,就像队列中写入一个消息
    q.put(file_name)


def main():
    # 1.获取用户要copy的文件夹名
    old_folder_name = input("请输入要copy的文件夹名:")

    # 2.创建一个新的文件夹
    try:
        new_folder_name = old_folder_name + "[附件]"
        os.mkdir(new_folder_name)
    except:
        pass

    # 3.获取文件夹中所有待copy文件名  os.listdir()
    file_names = os.listdir(old_folder_name)
    # print(file_names)

    # 4.创建进程池
    po = multiprocessing.Pool(5)

    # 5.创建队列
    '''在Pool中使用Queue要使用multiprocessing下Manage()类下的Queue()方法'''
    q = multiprocessing.Manager().Queue()

    # 6.向进程池中添加copy文件的人物
    for file_name in file_names:
        po.apply_async(copy_file, args=(q, file_name, old_folder_name, new_folder_name))
    
    po.close()
    ''' po.join() 改进代码让copy进度反馈来监控程序完成,
    就不需要join()了,因为只有都完成了,主程序才会结束'''
    all_file_num = len(file_names)  # 所有文件个数
    copy_ok_num = 0
    while True:
        file_name = q.get()
        # print("已经完成copy:%s" % file_name)
        copy_ok_num += 1
        print("\rcopy进度为:%.02f %%" % (copy_ok_num*100/all_file_num), end="")
        '''使进度显示在一行变化,显得更高大上一点
        重点在于行首增加\r,末尾增加end=""'''
        if copy_ok_num >= all_file_num:
            break
    print("")


if __name__ == "__main__":
    main()
>>[out]:请输入要copy的文件夹名:test
copy进度为:100.00 %
发布了33 篇原创文章 · 获赞 6 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/sinat_38354769/article/details/95590967
今日推荐