老男孩学习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内部的解释器去销毁的,(要做的就是把这些协程搞成闲置的线程)

 

posted on 2016-07-23 16:34  05_小翼  阅读(232)  评论(0编辑  收藏  举报

导航