您的位置:首页 > 编程语言 > Python开发

Python|多任务:线程、进程、协程--你想要的都在这里

2018-06-26 12:31 387 查看
版权声明:博客追求原创,如果有借鉴尽量都在文后注明 https://blog.csdn.net/DefaultTest/article/details/80813495

一、多任务——线程

1.前置知识:

  • 1.操作系统知识:操作系统调用方法--时间片轮转、时间优先级

  • 2.并发:假的多任务:CPU核心数小于同时需要执行的任务数;记忆:魔术师左右手互抛发球。

  • 3.并行:真的多任务

2.Pyhon 3.X中创建多线程的两种方法:

  • 2.1 法一:导入threading包的方法:

    关键几步代码: import threading t=threading.Thread(target=函数名,[args=(元组形式传入需要传递给调用函数的方法)]) # 调用threading的Thread类生成普通的实例对象;# 这里还需要注意的是,传递的是函数名,不能在函数名之后加(),否则就变成函数的嵌套调用 t.start() # 创建子线程并开始执行子线程。

  • 2.2 法二:threading.Thread()是一个类对象,可以作为父类被继承:

  • 关键几步代码:import threading class MyThread(threading.Thread):   def run(self):       pass t=MyThread() # 生成线程对象 t.start() ​ # 必须要有run方法,这样在实例对象调用start()的时候自动执行run()方法。注意:run()方法执行结束,该线程就结束。所以,可以在run方法中调用其他方法来间接执行其他方法。

3.主线程、子线程执行顺序

  • 3.1 多线程程序的执行顺序是不确定的 :实际上,主线程和子线程执行的顺序由操作系统决定,开启子线程需要时间,执行主线程也需要时间,这两个时间不确定。所以到底如何执行也不确定。

4.多线程产生的[资源竞争]问题及解决方案

  • 4.1 共享全局变量,实现多线程的设计优势,但是也存在资源竞争的问题,这个和语言无关,和操作系统的底层设计有关;

  • 4.2 解决方案——互斥锁

    threading.Lock()方法创建mutex对象,该对象调用acquire()和release()方法

  • 互斥锁之间的代码一般越少越好,但具体还看需求。

  • 4.3 互斥锁存在的问题:死锁 --> 互相等对方的资源

      [li]

      解决方案:添加超时时间、银行家算法等等

    [/li]


    二、多任务——进程

    1.基本定义、概念及前置知识

    • 1.1 操作系统 [写时拷贝(修改的时候才拷贝)]--操作系统概念,多进程基本代码是共享的一份,内存等资源会复制。

    • 1.2 一个程序一般可以有多个进程(辅助记忆:菜谱只有一份),每个进程在操作系统中对应一个PID。

    • 1.3 进程状态:就绪-->执行-->等待

    • 1.4 进程是系统分配资源的单位

    2.Pyhon 3.X中创建多进程的方法

    import multiprocessing
    ...
    p = muttiprocessing.Process(target=待调用的函数名, args=(元组形式传递待调用函数所需要的参数))
    p.start()
    ...
    ​
    # 创建队列
    q = multiprocessing.Queue()
    # 创建进程池
    po = multiprocessing.Pool()
    # 通过进程池实现进程间通信和多进程操作
    po.apply_async(待调用函数名,(传递给目标的参数元祖,))
    ...
    ​

    2.执行顺序

    • 2.1 进程运行无顺序 (前提是子进程开启):子进程、主进程运行顺序不确定

    • 2.2 join方法 -- 线程、进程

    3.进程间的通信

    • 3.1 socket -- 进程间网络通信

    • 3.2 Queue -- 通过[队列]实现进程间通信

      3.2.1 multiprocessing.Queue()实例对象有put()--存,get()--取等方法,其返回值是True、Flase等bool类型。

    • 3.2.2 扩展:1>单个进程间通信,列表等,直接用Queue模块;2>进程间通信--multiprocessing.Queue()和socket() ;3>涉及到进程池中子进程和主进程的通信,需要用到Multiprocessing.manager()中的Lock()和Queue()

  • 3.3 进程间不共享全局变量

  • 4.进程池 -- Pool

    • 4.1 进程管理器:在有大量的(不确定数量的)进程的时候,就可以让进程运行保持合理、高效的利用进程。进程的创建和销毁会占用大量的系统资源,如果一个进程结束可以让后面等待的进程继续使用这个系统资源,那么就可以提高系统资源利用率,这就是pool的威力。

    • 4.2 Pool().join() #阻塞 :进程池的主进程和多线程、多进程不同,主程序是不会等待子进程执行结束就可能关闭,所以必须要在关闭进程池之后添加一行po.join()方法,起到阻塞作用。

    • 4.3 特点:一些进程会继承之前进程池中的进程号

    • 4.4 要点1: 进程池中的进程产生异常可能不会报出异常,没法判断进程池中的进程是否执行.

    • 4.5 要点2:队列遇到进程池的时候,用

      multiprocessing.Manager().Queue()

    三、多任务 —— 协程

    1.前课知识

    • 1.1 from collections import Iterable,Iterator

    • 1.2 raise StopIteration 被python中的for...in...捕获

    • Python3.X 中 可迭代对象,占用很小的空间,存储的是生成结果的方式,而不是生成的结果。

    2.迭代器&生成器

    • 2.1 可迭代对象不等于迭代器,str、list、tuple、dict

    • 2.2 python特有的列表生成式[x for x in range(10)]、元组生成式;占用空间小。

    • 2.3 next();iter()方法

    • 2.4 yield 生成器--特殊的迭代器

    • 2.init方法每次返回同一个迭代器,不能多次迭代,每次返回不同的迭代器,可以多次迭代。

    3.迭代器-->生成器yield-->greenlet-->gevent,gevent打补丁

    # greenlet 用法关键
    from greenlet import greenlet
    ​
    gre1 = greenlet(待调用函数名)
    ​
    gre1.switch()
    # gevent 用法
    import gevent
    ​
    ​
    def fun(n):
       for i in range(n):
           print(gevent.getcurrent(), i)
           gevent.sleep(1)  # 非time.sleep()
    ​
    g1 = gevent.spawn(fun, 10)
    g2 = gevent.spawn(fun, 10)
    g1.join()
    g2.join()
    ​
    # gevent 打补丁及方法扩展
    ​
    from gevent import monkey
    import gevent
    import random
    import time
    ​
    ​
    # 有耗时操作时需要
    monkey.patch_all()  # 将程序中用到的耗时操作的代码,换为gevent中自己实现的模块
    ​
    ​
    def work(coroutine_name):
       for i in range(10):
           print(coroutine_name, i)
           time.sleep(random.random())
    ​
    gevent.joinall([
           gevent.spawn(work, "work1"),
           gevent.spawn(work, "work2")
    ])


    二、多任务——进程

    1.基本定义、概念及前置知识

    • 1.1 操作系统 [写时拷贝(修改的时候才拷贝)]--操作系统概念,多进程基本代码是共享的一份,内存等资源会复制。

    • 1.2 一个程序一般可以有多个进程(辅助记忆:菜谱只有一份),每个进程在操作系统中对应一个PID。

    • 1.3 进程状态:就绪-->执行-->等待

    • 1.4 进程是系统分配资源的单位

    2.Pyhon 3.X中创建多进程的方法

    import multiprocessing
    ...
    p = muttiprocessing.Process(target=待调用的函数名, args=(元组形式传递待调用函数所需要的参数))
    p.start()
    ...
    ​
    # 创建队列
    q = multiprocessing.Queue()
    # 创建进程池
    po = multiprocessing.Pool()
    # 通过进程池实现进程间通信和多进程操作
    po.apply_async(待调用函数名,(传递给目标的参数元祖,))
    ...
    ​

    2.执行顺序

    • 2.1 进程运行无顺序 (前提是子进程开启):子进程、主进程运行顺序不确定

    • 2.2 join方法 -- 线程、进程

    3.进程间的通信

    • 3.1 socket -- 进程间网络通信

    • 3.2 Queue -- 通过[队列]实现进程间通信

      3.2.1 multiprocessing.Queue()实例对象有put()--存,get()--取等方法,其返回值是True、Flase等bool类型。

    • 3.2.2 扩展:1>单个进程间通信,列表等,直接用Queue模块;2>进程间通信--multiprocessing.Queue()和socket() ;3>涉及到进程池中子进程和主进程的通信,需要用到Multiprocessing.manager()中的Lock()和Queue()

  • 3.3 进程间不共享全局变量

  • 4.进程池 -- Pool

    • 4.1 进程管理器:在有大量的(不确定数量的)进程的时候,就可以让进程运行保持合理、高效的利用进程。进程的创建和销毁会占用大量的系统资源,如果一个进程结束可以让后面等待的进程继续使用这个系统资源,那么就可以提高系统资源利用率,这就是pool的威力。

    • 4.2 Pool().join() #阻塞 :进程池的主进程和多线程、多进程不同,主程序是不会等待子进程执行结束就可能关闭,所以必须要在关闭进程池之后添加一行po.join()方法,起到阻塞作用。

    • 4.3 特点:一些进程会继承之前进程池中的进程号

    • 4.4 要点1: 进程池中的进程产生异常可能不会报出异常,没法判断进程池中的进程是否执行.

    • 4.5 要点2:队列遇到进程池的时候,用

      multiprocessing.Manager().Queue()

    三、多任务 —— 协程

    1.前课知识

    • 1.1 from collections import Iterable,Iterator

    • 1.2 raise StopIteration 被python中的for...in...捕获

    • Python3.X 中 可迭代对象,占用很小的空间,存储的是生成结果的方式,而不是生成的结果。

    2.迭代器&生成器

    • 2.1 可迭代对象不等于迭代器,str、list、tuple、dict

    • 2.2 python特有的列表生成式[x for x in range(10)]、元组生成式;占用空间小。

    • 2.3 next();iter()方法

    • 2.4 yield 生成器--特殊的迭代器

    • 2.init方法每次返回同一个迭代器,不能多次迭代,每次返回不同的迭代器,可以多次迭代。

    3.迭代器-->生成器yield-->greenlet-->gevent,gevent打补丁

    # greenlet 用法关键
    from greenlet import greenlet
    ​
    gre1 = greenlet(待调用函数名)
    ​
    gre1.switch()
    # gevent 用法
    import gevent
    ​
    ​
    def fun(n):
       for i in range(n):
           print(gevent.getcurrent(), i)
           gevent.sleep(1)  # 非time.sleep()
    ​
    g1 = gevent.spawn(fun, 10)
    g2 = gevent.spawn(fun, 10)
    g1.join()
    g2.join()
    ​
    # gevent 打补丁及方法扩展
    ​
    from gevent import monkey
    import gevent
    import random
    import time
    ​
    ​
    # 有耗时操作时需要
    monkey.patch_all()  # 将程序中用到的耗时操作的代码,换为gevent中自己实现的模块
    ​
    ​
    def work(coroutine_name):
       for i in range(10):
           print(coroutine_name, i)
           time.sleep(random.random())
    ​
    gevent.joinall([
           gevent.spawn(work, "work1"),
           gevent.spawn(work, "work2")
    ])

    阅读更多
    内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
    标签: