多任务--线程

进程

一、概念

二、进程的创建和操作

三、进程通信--Queue

四、进程池

五、进程与线程区别

六、案例

回到顶部

一、概念

1.概念

  进程: 通俗理解一个运行的程序或者软件,进程是操作系统资源分配的基本单位。

  注意: 一个程序至少有一个进程,一个进程至少有一个线程,多进程可以完成多任务.

2.进程的执行状态

  工作中,任务数往往大于cpu的核数,即一定有一些任务正在执行,而另外一些任务在等待cpu进行执行,因此导致了有了不同的状态

 

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

二、进程的创建和操作

1.进程的创建

  创建进程 : pro = multiprocessing.Process(target=入口, args=(), kwargs={})

  开始执行 : pro.start()

2.进程的操作

  pro.join() 一直等待 死等

​       pro.join(2) 阻塞等待子进程2秒 如果子进程没有终止那主进程就直接往下执行

​     pro.terminate() 终止子进程

​     pro.is_alive() 判断子进程状态

#!/usr/bin/env python
# _*_ coding:utf-8 _*_
# Author:Mr.yang
import multiprocessing
import time
import os

def pro_info(info, data):
    """子进程 运行的代码"""
    for i in range(30):
        print("这是子进程 info=%s data=%s PID=%s PPID=%s" % (info,data,os.getpid(),os.getppid()))
        time.sleep(1)

def main():
    """单进程 单线程模式 主进程"""
    # 创建子进程
    pro = multiprocessing.Process(target=pro_info, args=("今天天气不错",), kwargs={"data":"50"}, name="陈特特")
    # 创建 启动子进程
    pro.start()

    # 主进程阻塞等待子进程 2秒 / 如果能等到子进程退出 回收子进程的资源
    pro.join(2)
    print("获取子进程的pid = %s name = %s" % (pro.pid,pro.name))
    print("===============================")

    # 判断子进程是否存活
    print(pro.is_alive())

    # # 终止子进程 像操作系统发出一个 终止子进程的信号 存在延迟 不要立即判断子进程的状态
    # pro.terminate()
    # 判断子进程是否存活
    print(pro.is_alive())
    print("===============================")

    for i in range(3):
        # 查看当前所在进程的PID
        print("这是主进程 PID=%s" % os.getpid())
        time.sleep(1)

if __name__ == '__main__':
    main()
示例代码

三、进程通信--Queue

  1.使用队列Queue的原因

    原因: 进程间不共享全局资源

    Queue 是一种进程间通信的方式, 先进先出

  2.使用方法

  • 创建 队列对象 = multiprocessing.Queue(长度)
  • 放 队列对象.put(数据)
  • 取 数据 = 队列对象.get()
  • 判断空 队列对象.empty()
  • 判断满 队列对象.full()
  • 数量 队列对象.qsize()
    import multiprocessing
    import time
    
    
    def proc_func(q):
        """子进程入口"""
        while True:
            time.sleep(3)
            # 判断空
            if q.empty():
                print("队列中已经没有了 稍后再来")
                time.sleep(3)
            # 从队列中取出数据
            data = q.get()
            print("从队列中取出了数据%s" % data)
    
    def main():
        pass
        # 1 创建出来 主进程和子进程通信所需的 队列对象
        q = multiprocessing.Queue(3)
    
        # 2 创建子进程 
        pro = multiprocessing.Process(target=proc_func, args=(q,))
        pro.start()
    
        while True:
            # 3 接收输入 放入队列中
            data = input(":")
            # 判断队列满 
            if q.full():
                print("慢点输入已经满了 马上溢出了")
                time.sleep(1)
            # 向队列中放入数据
            q.put(data)
    
    if __name__ == '__main__':
        main()
    示例

四、进程池

1.工作模式

  模式提前创建一批进程, 重复利用已经空闲的进程执行 多任务

  优点 :  节约了 大量进程的创建/销毁的开销, 提高任务的响应速度

2.添加任务两种方式

  同步方式 : 会阻塞等待添加任务的执行完成后才会继续往下执行

​     异步方式 :只添加任务 不会等待任务执行完成

3.使用步骤和注意事项   

1 创建进程池  进程池对象 = multiprocessing.Pool(工作进程的数量)        

2 添加任务      

    同步  进程池对象.apply(入口)  添加任务并等待任务执行完成

    异步  进程池对象.apply_async(入口)  只添加任务 不等待任务完成

3 关闭进程池

    进程池对象.close()  不允许添加新任务

4 等待所有任务执行完成

    进程池对象.join()

  注意:进程池之间的进程通信不能使用multiprocessing.Queue 而应该使用 multiprocessing.Manager().Queue

五、进程与线程区别

  1.区别   

  • 进程之间不共享全局变量
  • 线程之间共享全局变量,但是要注意资源竞争的问题,解决办法: 互斥锁或者线程同步
  • 创建进程的资源开销要比创建线程的资源开销要大
  • 进程是操作系统资源分配的基本单位,线程是CPU调度的基本单位
  • 线程不能够独立执行,必须依存在进程中
  • 多进程开发比单进程多线程开发稳定性要强

  2.优缺点    

  多进程:

      • 优点:可以用多核
      • 缺点:资源开销大

  多线程:

      • 优点:资源开销小
      • 缺点:不能使用多核

  3.功能对比

    • 进程,能够完成多任务,比如 在一台电脑上能够同时运行多个QQ
    • 线程,能够完成多任务,比如 一个QQ中的多个聊天窗口

  4.定义对比

    • 进程是系统进行资源分配基本单位,每启动一个进程操作系统都需要为其分配运行资源。
    • 线程是运行程序中的一个执行分支,是CPU调度基本单位。
    • 总结:进程是操作系统资源分配的基本单位,线程是CPU调度的基本单位

六、案例

#!/usr/bin/env python
# _*_ coding:utf-8 _*_
# Author:Mr.yang
import multiprocessing
import os

def copy_file(src_path, dest_path, file):
    """从源目录下 将file对应的文件数据读取并且写到目的目录下 file文件中"""
    # 1.打开源目录下的文件用以读
    src_file = open(src_path + "/" + file, "rb")
    print(dest_path + "/" + file)

    # 2.打目的目录下的文件用以写
    dest_file = open(dest_path + "/" + file, "wb")

    # 3.一遍从源文件中读取数据 写入目的文件中
    while True:
        file_data = src_file.read(1024)
        if not file_data:
            print("%s文件拷贝完成" % file)
            break
        dest_file.write(file_data)
    # 4.完成后  关闭源文件 关闭目的文件中
    src_file.close()
    dest_file.close()

def main():
    # 1.用户输入备份的目录
    source_path = input("请输入要备份的目录:")

    # 2.根据源目录创建一个目的目录 源目录-备份
    dest_path = source_path + "-备份"
    os.mkdir(dest_path)

    # 3.根据源目录去获取源目录下所有的 文件名称
    file_list = os.listdir(source_path)
    # print(file_list)

    # 4.根据每个源文件的名称 读取出每个文件的数据 将数据写入到 目的目录/源文件
    for file in file_list:
        pro = multiprocessing.Process(target=copy_file, args=(source_path, dest_path, file))
        pro.start()


if __name__ == '__main__':
    main()
备份当前目录---多进程
#!/usr/bin/env python
# _*_ coding:utf-8 _*_
# Author:Mr.yang
import multiprocessing
import time
import os

def copy_file(src_path, dest_path, file, q):
    """从源目录下 将file对应的文件数据读取并且写到目的目录下 file文件中"""
    # 1.打开源目录下的文件用以读
    src_file = open(src_path + "/" + file, "rb")

    # 2.打目的目录下的文件用以写
    dest_file = open(dest_path + "/" + file, "wb")

    # 3.一遍从源文件中读取数据 写入目的文件中
    while True:
        file_data = src_file.read(1024)
        if not file_data:
            # print("%s文件拷贝完成" % file)
            break
        dest_file.write(file_data)
    # 4.完成后  关闭源文件 关闭目的文件中
    src_file.close()
    dest_file.close()
    # 5.当任务完成后 向队列中添加一个消息 表示完成
    q.put(file)

def main():
    # 1.用户输入备份的目录
    source_path = input("请输入要备份的目录:")

    # 2.根据源目录创建一个目的目录 源目录-备份
    dest_path = source_path + "-备份"
    os.mkdir(dest_path)

    # 3.根据源目录去获取源目录下所有的 文件名称
    file_list = os.listdir(source_path)
    # print(file_list)

    # 4.根据每个源文件的名称 读取出每个文件的数据 将数据写入到 目的目录/源文件
    # 使用进程池处理每个任务
    # 4.0 创建出一个队列 用于进程间通信 不能使用multiprocessing.Queue(10)
    # q = multiprocessing.Queue(10)
    q = multiprocessing.Manager().Queue(10)

    # 4.1 创建进程池
    p = multiprocessing.Pool(4)

    # 4.2 添加任务到进程池中
    for file in file_list:
        p.apply_async(copy_file,args=(source_path, dest_path, file, q))
    # 4.3 关闭进程池
    p.close()

    # 从队列中取出消息
    count = 0
    while True:
        if count == len(file_list):
            break
        q.get()
        count += 1
        print("
当前进度是%.2f %%" % ((count/len(file_list))*100), end="")
        time.sleep(0.1)

    # 4.4 等待进程池所有任务都执行完成
    p.join()


if __name__ == '__main__':
    main()
备份当前目录---进程池
原文地址:https://www.cnblogs.com/Mryang123/p/9997738.html