zoukankan      html  css  js  c++  java
  • 老男孩学习DAY11-1 进程、进程池、协程

    python 进程

    优点:可以处理大量的并发操作,使用IO计算型

    缺点:由于进程之间的数据都是独立,所以创建一个进程,就得消耗一份内存 (进程和cpu核数相同的情况最好)

    Process :进程 (让我想到了40个人,要烧40壶水,要弄40个炉子,但是效率高)

    进程中有 join (2)   阻塞住啦,最多阻塞2秒钟;demaon(true)  可以设置不阻塞,直接运行。

    都说进程之间的数据是独立,那么我们你能将进程之间的数据共享吗,聪明的人类,当然可以,那就用到了mange和array

    arrary 这个东西 就是将一个列表转换成一个特殊的数据类型(数组),manage 方式数据共享

    from multiprocessing import Process
    from multiprocessing import Manager
    import time
    if __name__ == '__main__':
        manage = Manager()
        dic = manage.list()
        def foo(i):
            dic[i]=100+i
            print (dic.values())
        for i in range(10):
            p = Process(target=foo,args=(i,))
            p.start()
        print(dic.values())

    这个思路太混啦,不过老师说,这个进程数据共享用的不多,n

    进程池

    进程池内部维护一个进程序列,当使用时,则去进程池中获取一个进程,如歌进程池中没有可供使用的进程池,那么程序就会等待,直到进程池有可用的进程为止

    进程池有两个方法:

    • apply(同步)
    • apply_async(异步)

    协程

    线程和进程的操作是由程序触发接口,最后的执行者是系统,协程的操作则是程序员

    协程存在的意义;对于多线程的应用,cpu通过切片的方式来切换线程间的执行,线程切换时需要耗时(保存状态,下次继续)。协程,则只使用一个线程,在一个线程中规定某个代码块执行顺序

    协程的使用场景:当程序中存在大量不需要CPU的操作时(IO)

    武老师 高级版线程池

    #!/usr/bin/env python
    #-*- coding:utf-8 -*-
    import queue
    import threading
    import contextlib
    #创建一个终止符
    StopEvent = object()
    #创建一个类
    class ThreadPool(object):
    
        def __init__(self, max_num):
            #创建一个任务列队
            self.q = queue.Queue(max_num)
            #定义这个任务队列的大小
            self.max_num = max_num
            self.cancel = False
            #真实创建线程列表
            self.generate_list = []
            #等待线程的列表
            self.free_list = []
    
        def run(self, func, args, callback=None):
            """
            线程池执行一个任务
            :param func: 任务函数
            :param args: 任务函数所需参数
            :param callback: 任务执行失败或成功后执行的回调函数,回调函数有两个参数1、任务函数执行状态;2、任务函数返回值(默认为None,即:不执行回调函数)
            :return: 如果线程池已经终止,则返回True否则None
            """
            if self.cancel:
                return True
            #如果等待的线程列表是空的,并且真实创建的线程列表小于任务的数量(创建的线程不可能大于任务数量)
            if len(self.free_list) == 0 and len(self.generate_list) < self.max_num:
                #执行任务
                self.generate_thread()
            #任务是一个元祖,其中callback是个回掉函数,也可以有,也可以没有
            w = (func, args, callback,)
            #将任务放入队列
            self.q.put(w)
        #执行任务
        def generate_thread(self):
            #创建一个线程,去处理任务,(call就是处理任务的函数)
            t = threading.Thread(target=self.call)
            #启动该线程
            t.start()
        #任务是一个元祖,用call方法来处理一个任务
        def call(self):
            #获取当前的线程
            current_thread = threading.currentThread
            #将线程加入线程池列表
            self.generate_list.append(current_thread)
            #将获取的任务赋值给event
            event = self.q.get()
            #当获取的任务还是任务时(前边已经将任务封装成了元祖)
            while event != StopEvent:
                #将任务赋值给event
                func, arguments, callback = event
                #去处理任务
                try:
                    result = func(arguments)
                #如果处理成功,返回成功,并将任务结果返回
                    success = True
                #处理失败,也告诉队列,并将任务结果重置成空
                except Exception as e:
                    success = False
                    result = None
                #如果任务成功,并且且返回了成功,就执行回掉函数
                if callback is not None:
                    try:
                        callback(success, result)
                    except Exception as e:
                        pass
                #将当前线程加入真实线程池列表
                self.generate_list.append(current_thread)
                #然后再去获取任务
                event = self.q.get()
                #因为这个线程还要去工作呢,所以将线程从线程池里面拿出来去执行任务
                self.generate_list.remove(current_thread)
            else:
                #如果任务不是任务啦,从真实的线程里面移除这个线程
                self.generate_list.remove(current_thread)
    
        def terminal(self):
            """
            终止线程池中的所有线程
            """
            self.cancel = True
            full_size = len(self.generate_list)
            while full_size:
                self.q.put(StopEvent)
                full_size -= 1
    
        def stop(self):
            full_size = len(self.generate_list)
            while full_size:
                self.q.put(StopEvent)
                full_size -= 1
    
    
       # # @contextlib.contextmanager
       #  def worker_state(self, generate_list, current_thread):
       #      """
       #      用于记录线程中正在等待的线程数
       #      """
       #      generate_list.append(current_thread)
       #      try:
       #          yield
       #      finally:
       #          generate_list.remove(current_thread)
    
    
    def show(arg):
        import time
        # time.sleep(1)
        print (arg)
    
    #创建了最大为20个线程池
    pool = ThreadPool(10)
    #定了500个任务
    for i in range(100):
        pool.run(func=show, args=(i,))
        pool.stop()

    武老师的线程池关键点


    1、创建了一个任务的队列


    2、自己定了一个最大为多少的线程池 (只是定了最大的数量,并没有自己创建),这个数量根据你自己的配置,设计好了最优的数量


    3、线程的创建不是人为创建的,是操作系统根据任务的耗时自己创建的

    3.1如果人为的根据任务的数量去创建线程,有可能任务很短,有好多事用不到,那这样就造成了浪费
    3.2这点让我想起了协程,协程不久认为代替操作系统去接管处理任务吗,如果能将协程代码嵌套进来,会不会更好,但是协程内部代码太复杂,搞不定。


    4、闲置的线程被销毁,这个操作肯定python内部的解释器去销毁的,(要做的就是把这些协程搞成闲置的线程)

  • 相关阅读:
    js 读取XML
    JavaScript DOM 交换节点笔记
    JDBC学习总结 -- JDBC 快速入门 教程
    SQL 语句易错点讲解
    JAVA 他人博客收藏 (To be continue)
    <<MYSQL必知必会>> 入坑指南
    OpenGL 纹理学习总结
    BZOJ 3456 NTT图的计数 容斥
    洛谷1002 容斥原理+dfs OR DP
    51nod1565 FFT
  • 原文地址:https://www.cnblogs.com/05-xiaoyi/p/5698993.html
Copyright © 2011-2022 走看看