• Python--多任务(多进程,多线程,协程)


    1.单核CPU实现“多任务”:(注意:这里的多任务假的,是轮训执行多个任务一段时间)

          1)时间片轮转

          2)优先级调度算法

    2.并行:真的多任务执行(CPU核数>=任务数);即在某个时刻点上,有多个程序同时运行在多个CPU上

    3.并发:假的多任务执行(CPU核数<任务数);即一段时间内,有多个程序在同一个CPU上运行

    4.多线程执行的顺序不确定

    5.没运行的程序是程序,运行的程序就是进程

    6.进程/线程:

       1)子进程把主进程所有的资源复制一份,子进程拥有主进程的所有资源,代码是共享的

       2)进程耗费的资源大,线程占用的资源少

       3)代码---》进程---》主线程---》多个子线程

       4)进程是系统资源分配的单位,线程是系统调度的单位

       5)一般进程不能共享

       6)通过进程之间的通信实现共享(通过socket,文件,队列Queue实现)

            a.队列实现:

                    创建多个子进程,将队列的引用(即变量)当做实参进行传递到进程里面

       7)进程池Pool

            a.先创建一部分进程,来了大量任务>进程数,通过排队调度实现重复利用

            b.如果定义的最大进程池数大于创建进程数,不会出现阻塞,但是只是开启最大进程池的数量,剩余的进程处于等待调度,主进程可以先结束,进程池后结束,可以通过po.join()阻塞等待进程池中的子进程执行完后主进程执行完,图例:

             

        

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    # @File  : 多进程--实现文件夹拷贝.py
    # @Author: Liugp
    # @Date  : 2019/5/22
    # @Desc  :
    import os
    import multiprocessing
    
    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()
    
        # 如果拷贝完了文件,那么就想队列中写入一个消息,表示已经完成
        q.put(file_name)
    
    
    def main():
        # 1.获取用户要copy的文件夹的名字
        old_folder_name = input("请输入要copy的文件夹的名字:")
    
        # 2.创建一个新的文件夹
        try:
            new_folder_name = input("请输入要copy的文件夹的名字:")
            os.mkdir(new_folder_name)
        except Exception as e:
            pass
    
        # 3.获取文件的所有的待copy的文件名字 listdir()
        file_names = os.listdir(old_folder_name)
        # print(file_names)
    
        # 4.创建进程池
        po = multiprocessing.Pool(5)
    
        # 5.创建一个队列
        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()
        all_file_num = len(file_names) # 获取所以文件的个数
        copy_ok_num = 0
        while True:
            file_name = q.get()
            # print("已完成%s" % file_name)
            copy_ok_num += 1
            print("
    拷贝的进度为:%.2f %%" % (copy_ok_num*100/all_file_num),end='')
            if copy_ok_num >= all_file_num:
                break
        print()
    
    
    if __name__ == "__main__":
        main()

    7.多任务--协程

        a.迭代器:

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    # @File  : 迭代器-demo2.py
    # @Author: Liugp
    # @Date  : 2019/5/22
    # @Desc  :
    import time
    from collections import Iterable
    from collections import Iterator
    class Classmate(object):
        def __init__(self):
            self.names = list()
            self.current_num = 0
    
        def add(self,name):
            self.names.append(name)
    
        def __iter__(self):
            """如果想要一个对象称为一个可以迭代的对象,即可以使用for,那么必须实现__iter__方法"""
            return self
    
        def __next__(self):
            if self.current_num < len(self.names):
                ret = self.names[self.current_num]
                self.current_num += 1
                return ret
            else:
                raise StopIteration
    
    if __name__ == '__main__':
        classmate = Classmate()
        classmate.add('老王')
        classmate.add('王二')
        classmate.add('张三')
    
        # print("判断classmate是否是可以迭代的对象:",isinstance(classmate,Iterable))
        # classmate_iterator = iter(classmate)
        # print("判断classmate_iterator是否是迭代器:",isinstance(classmate_iterator,Iterator))
        # print(next(classmate_iterator))
    
        for item in classmate:
            print(item)
            time.sleep(1)
    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    # @File  : 迭代器--斐波那契数列.py
    # @Author: Liugp
    # @Date  : 2019/5/23
    # @Desc  :
    
    class Fibonacci(object):
        def __init__(self,all_num):
            self.all_num = all_num
            self.current_num = 0
            self.a = 0
            self.b = 1
    
        def __iter__(self):
            return self
    
        def __next__(self):
            if self.current_num < self.all_num:
                ret = self.a
    
                self.a,self.b = self.b,self.a+self.b
                self.current_num += 1
    
                return ret
            else:
                raise StopIteration
    
    
    if __name__ == "__main__":
        fibo = Fibonacci(10)
        for num in fibo:
            print(num)

       b.生成器==特殊的迭代器

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    # @File  : 迭代器--斐波那契数列.py
    # @Author: Liugp
    # @Date  : 2019/5/23
    # @Desc  :
    
    def create_num(all_num):
        # a = 0
        # b = 1
        a, b = 0, 1
        current_num = 0
        while current_num < all_num:
            yield a
            a, b = b, a+b
            current_num += 1
    
    
    if __name__ == "__main__":
        # 如果在调用create_num的时候,发现这个函数有yield,那么此时,不是调用函数,而是创建一个生成器对象
        obj = create_num(10)
        for num in obj:
            print(num)
    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    # @File  : 迭代器--斐波那契数列--研究.py
    # @Author: Liugp
    # @Date  : 2019/5/23
    # @Desc  :
    
    def create_num(all_num):
        # a = 0
        # b = 1
        a, b = 0, 1
        current_num = 0
        while current_num < all_num:
            yield a
            a, b = b, a+b
            current_num += 1
    
    if __name__ == "__main__":
        obj = create_num(50)
        # 如果在调用create_num的时候,发现这个函数有yield,那么此时,不是调用函数,而是创建一个生成器对象
        while True:
            try:
                ret = next(obj)
                print(ret)
            except Exception as ret:
                break
    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    # @File  : 迭代器--斐波那契数列--研究.py
    # @Author: Liugp
    # @Date  : 2019/5/23
    # @Desc  :
    
    def create_num(all_num):
        # a = 0
        # b = 1
        a, b = 0, 1
        current_num = 0
        while current_num < all_num:
            ret = yield a
            print(">>>>ret>>>>",ret)
            a, b = b, a+b
            current_num += 1
    
    if __name__ == "__main__":
        obj = create_num(10)
        # 如果在调用create_num的时候,发现这个函数有yield,那么此时,不是调用函数,而是创建一个生成器对象
        ret = next(obj)
        print(ret)
    
        ret = obj.send("hahahaha")
        print(ret)

     协程:

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    # @File  : 多任务yield-demo1.py
    # @Author: Liugp
    # @Date  : 2019/5/27
    # @Desc  :
    import time
    
    def task_1():
        while True:
            print('-----1-----')
            time.sleep(0.1)
            yield
    
    def task_2():
        while True:
            print('-----2-----')
            time.sleep(0.1)
            yield
    
    def main():
        t1 = task_1()
        t2 = task_2()
        while True:
            next(t1)
            next(t2)
    
    if __name__ == "__main__":
        main()

    简单总结:

    1.进程是资源分配的单位

    2.线程是操作系统调度的单位

    3.进程切换需要的资源很大,效率最低

    4.线程切换需要的资源一般,效率一般(当然了在不考虑GIL的情况下)

    5.协程切换任务资源很小,效率高

    6.多进程、多线程根据CPU核数不一样可能是并行的,但是协程是在一个线程中,所以是并发

  • 相关阅读:
    CodeBlocks下载与安装教程
    Delphi 资源管理器套件
    做了一个 62 进制的简单实现
    关于 TRegEx.Split()
    Delphi 的链式代码
    在Linux上编译dotnet cli的源代码生成.NET Core SDK的安装包
    尝试解决在构造函数中同步调用Dns.GetHostAddressesAsync()引起的线程死锁
    .NET Core中遇到奇怪的线程死锁问题:内存与线程数不停地增长
    将asp.net core站点发布到IIS上遇到的问题
    .NET Core 构建配置文件从 project.json 到 .csproj
  • 原文地址:https://www.cnblogs.com/liugp/p/10878746.html
Copyright © 2020-2023  润新知