网络编程(4) - 多任务-进程

125 阅读5分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

多任务-进程

4.1,进程及状态

  1. 进程

    1. 程序:硬盘上,u盘上面的exe(二进制文件)可执行文件是死的
    2. 进程运行起来的程序叫进程,运行的 进程 能够使用资源(键盘,摄像头,网络)
  2. 进程的状态

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

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-90fWULQy-1592064669629)(assets/.png)]

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

4.2,进程(重点)

  1. 使用进程来进行多任务

    用法与threading线程相类似

    查看线程状态(Linux下):ps -aux

    杀死某个进程(Linux下):kill 进程ID

     # !/usr/bin/env python
     # _*_ coding:utf-8 _*_
     # author:满怀心 2019/8/3 13:40
     """
     # code is far away from bugs with the god animal protecting
         I love animals. They taste delicious.
                   ┏┓      ┏┓
                 ┏┛┻━━━┛┻┓
                 ┃      ☃      ┃
                 ┃  ┳┛  ┗┳  ┃
                 ┃      ┻      ┃
                 ┗━┓      ┏━┛
                     ┃      ┗━━━┓
                     ┃  神兽保佑    ┣┓
                     ┃ 永无BUG!   ┏┛
                     ┗┓┓┏━┳┓┏┛
                       ┃┫┫  ┃┫┫
                       ┗┻┛  ┗┻┛
     """
     import time
     import multiprocessing
     
     
     def text1():
         while True:
             print('1----------')
             time.sleep(1)
             return
             
     
     
     def text2():
         while True:
             print('2----------')
             time.sleep(1)
     
     
     def main():
         t1 = multiprocessing.Process(target=text1)
         t2 = multiprocessing.Process(target=text2)
         t1.start()
         t2.start()
     
     
     if __name__ == '__main__':
         main()
    

    能实现多任务,但是占用资源大

    写时拷贝:(如果中途代码发生改变,所有子进程都会改变)

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NLfdYOGK-1592064669633)(assets/.png)]

4.3,线程和进程的区别

  1. 功能

    • 进程 : 能完成多任务,比如电脑上开多个QQ,是资源的总称
    • 线程 : 能完成多任务,比如QQ上开多个聊天窗口,轻量级
    注意:
    1. 先有进程才有线程,线程是拿着进程的资源去运行的,一个进程里面至少有一个主线程
    2. 线程的划分尺度小于进程(资源比进程少),使得多线程程序的并发性高
    3. 进程是资源分配的单位线程是资源调度(执行)的单位。在一个进程里,线程之间资源共享,极大的提高了程序的运行速度

    多线程:一个进程里面有多个线程执行任务 多进程:多个进程里面有一个或多个线程执行任务

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-z8DDFfRw-1592064669637)(assets/.png)]

    • 线程不能够独立执行,必须依存在进程中
    • 可以将进程理解工厂里的一条流水线,而其中的线程就是这个流水线上的工人

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-z90gzvGg-1592064669639)(assets/.jpg)]

优缺点:线程和进程在使用上各有优缺点:线程执行开销小,但是不利于资源的管理和保护;而进程相反

4.4,进程间的通信

Process之间有时需要通信,操作系统提供了很多机制来实现进程间的通信,降低程序耦合度

  1. Queue的使用

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

    # !/usr/bin/env python
    # _*_ coding:utf-8 _*_
    # author:满怀心 2019/8/4 15:01
    """
    # code is far away from bugs with the god animal protecting
        I love animals. They taste delicious.
                  ┏┓      ┏┓
                ┏┛┻━━━┛┻┓
                ┃      ☃      ┃
                ┃  ┳┛  ┗┳  ┃
                ┃      ┻      ┃
                ┗━┓      ┏━┛
                    ┃      ┗━━━┓
                    ┃  神兽保佑    ┣┓
                    ┃ 永无BUG!   ┏┛
                    ┗┓┓┏━┳┓┏┛
                      ┃┫┫  ┃┫┫
                      ┗┻┛  ┗┻┛
    """
    import multiprocessing
    
    
    def download_from_web(q):
        """下载数据"""
        data = [1, 2, 3, 4]
    
        for i in data:
            q.put(i)
    
        print('数据已经全部添加到队列')
    
    
    
    def analysis_data(q):
        """数据处理"""
        waiting_analysis_data = list()
        while True:
            data = q.get()
    
            if q.empty():
                break
        print('数据处理完毕')
    
    
    def main():
        q = multiprocessing.Queue()
    
        t1 = multiprocessing.Process(target=download_from_web, args=(q, ))
        t2 = multiprocessing.Process(target=analysis_data, args=(q, ))
    
        t1.start()
        t2.start()
    
    
    
    if __name__ == '__main__':
        main()
    

4.5,进程池

能够重复利用进程里面的进程

 # !/usr/bin/env python
 # _*_ coding:utf-8 _*_
 # author:满怀心 2019/8/4 16:41
 """
 # code is far away from bugs with the god animal protecting
     I love animals. They taste delicious.
               ┏┓      ┏┓
             ┏┛┻━━━┛┻┓
             ┃      ☃      ┃
             ┃  ┳┛  ┗┳  ┃
             ┃      ┻      ┃
             ┗━┓      ┏━┛
                 ┃      ┗━━━┓
                 ┃  神兽保佑    ┣┓
                 ┃ 永无BUG!   ┏┛
                 ┗┓┓┏━┳┓┏┛
                   ┃┫┫  ┃┫┫
                   ┗┻┛  ┗┻┛
 """
 from multiprocessing import Pool
 import os, time, random
 
 
 def worker(msg):
     t_start = time.time()
     print('{} 开始执行,进程号为 : {}'.format(msg, os.getpid()))
     time.sleep(random.random()*2)
     t_stop = time.sleep()
     print('{} 结束执行,耗时{:2f}'.format(msg, (t_stop-t_start)))
     
 po = Pool(3)    # 定义一个进程池,最大进程数为3
 for i in range(10):
     po.apply_async(worker, (i, ))
     
 print('-----start-----')
 po.close()  # 关闭进程池,关闭后po不在接收新的请求
 po.join()   # 阻塞进程,等待po中所有的子进程执行完毕,必须放在close语句后,不然主死子死
 print('-----stop-----')
运行结果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wez6jwho-1592064669642)(assets/.png)]

4.6,文件夹的拷贝器(多进程版本)

文件的复制:用rb读取旧文件,创建新文件,用wb写入

 # !/usr/bin/env python
 # _*_ coding:utf-8 _*_
 # author:满怀心 2019/8/4 21:53
 """
 # code is far away from bugs with the god animal protecting
     I love animals. They taste delicious.
               ┏┓      ┏┓
             ┏┛┻━━━┛┻┓
             ┃      ☃      ┃
             ┃  ┳┛  ┗┳  ┃
             ┃      ┻      ┃
             ┗━┓      ┏━┛
                 ┃      ┗━━━┓
                 ┃  神兽保佑    ┣┓
                 ┃ 永无BUG!   ┏┛
                 ┗┓┓┏━┳┓┏┛
                   ┃┫┫  ┃┫┫
                   ┗┻┛  ┗┻┛
 """
 import os
 import multiprocessing
 
 
 def copy_file(index, file_name, old_folder_name, new_folder_name):
     print('-----模拟copy文件, 从{} => {}, 当前文件 {} : {}-----'.format(old_folder_name, new_folder_name, index, file_name))
 
     old_f = open(r'{}/{}'.format(old_folder_name, file_name), 'rb')
     content = old_f.read()
     old_f.close()
 
     new_f = open(r'{}/{}'.format(new_folder_name, file_name), 'wb')
     new_f.write(content)
     new_f.close()
 
 
 def main():
     # 1. 获取用户要copy的文件夹的名字
     old_folder_name = input('请输入要copy的文件夹名:\t')
 
 
     # 2. 创建一个新的文件夹
     new_folder_name = '[复制]{}'.format(old_folder_name)
     try:
         os.mkdir(new_folder_name)
     except Exception:
         pass
     # 3. 获取文件夹下所有文件的名字
     file_names = os.listdir(old_folder_name)
     # print(file_names)
 
     # 4. 创建进程池
     po = multiprocessing.Pool(5)
 
     # 5. 向进程池里面添加 copy 文件的任务
     for index, file_name in enumerate(file_names):
         po.apply_async(copy_file, args=(index, file_name, old_folder_name, new_folder_name))
 
     po.close()  # 停止向进程池提交任务
     po.join()   # 阻塞主进程,等待子进程结束
 
 if __name__ == '__main__':
     main()
-添加进度条版
 # !/usr/bin/env python
 # _*_ coding:utf-8 _*_
 # author:满怀心 2019/8/4 21:53
 """
 # code is far away from bugs with the god animal protecting
     I love animals. They taste delicious.
               ┏┓      ┏┓
             ┏┛┻━━━┛┻┓
             ┃      ☃      ┃
             ┃  ┳┛  ┗┳  ┃
             ┃      ┻      ┃
             ┗━┓      ┏━┛
                 ┃      ┗━━━┓
                 ┃  神兽保佑    ┣┓
                 ┃ 永无BUG!   ┏┛
                 ┗┓┓┏━┳┓┏┛
                   ┃┫┫  ┃┫┫
                   ┗┻┛  ┗┻┛
 """
 import os
 import multiprocessing
 
 
 def copy_file(index, file_name, old_folder_name, new_folder_name, q):
     # print('-----模拟copy文件, 从{} => {}, 当前文件 {} : {}-----'.format(old_folder_name, new_folder_name, index, file_name))
 
     old_f = open(r'{}/{}'.format(old_folder_name, file_name), 'rb')
     content = old_f.read()
     old_f.close()
 
     new_f = open(r'{}/{}'.format(new_folder_name, file_name), 'wb')
     new_f.write(content)
     new_f.close()
 
     # 如果拷贝完了文件,那就向队列中写入一个消息,表示已经完成
     q.put(file_name)
 
 
 def main():
     # 1. 获取用户要copy的文件夹的名字
     old_folder_name = input('请输入要copy的文件夹名:\t')
 
 
     # 2. 创建一个新的文件夹
     new_folder_name = '[复制]{}'.format(old_folder_name)
     try:
         os.mkdir(new_folder_name)
     except Exception:
         pass
     # 3. 获取文件夹下所有文件的名字
     file_names = os.listdir(old_folder_name)
     # print(file_names)
 
     # 4. 创建进程池
     po = multiprocessing.Pool(5)
 
     # 5. 创建队列
     q = multiprocessing.Manager().Queue()
 
     # 6. 向进程池里面添加 copy 文件的任务
     for index, file_name in enumerate(file_names):
         po.apply_async(copy_file, args=(index, file_name, old_folder_name, new_folder_name, q))
 
     po.close()  # 停止向进程池提交任务
     # po.join()   # 阻塞主进程,等待子进程结束
     all_file_num = len(file_names)  # 测量所有文件的数量
     copy_file_num = 0
     while True:
         file_name = q.get()
         # print('-----{}已经完成copy-----'.format(file_name))
         copy_file_num += 1
         print('\r拷贝的进度为 {:.0f}%'.format(copy_file_num/all_file_num*100), end='')
         if copy_file_num == all_file_num:	# 所有文件copy完成
             break
     
     print()
 
 
 if __name__ == '__main__':
     main()

运行结果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4c0BpGGA-1592064669643)(assets/.png)]