• 线程池和进程池以及线程queue


    线程queue

    既然有进程的队列,那么也会有线程的queue

    线程的queue有三种方式

    并且导入模块的方式和进程不一样

    先进先出

    import queue
    q = queue.Queue()#
    q.put('123')
    q.put('qweqwe')
    print(q.get())
    print(q.get())
    # print(q.get())
    q.task_done()
    q.task_done()
    q.join()
    

    123
    qweqwe

    和之前的joinablequeue一样,这个需要用task_done来减掉计数器的值。不然join那里就会一直阻塞住。这是先进先出。

    先进后出

    q = queue.LifoQueue() #堆栈 先进后出
    q.put('粉红色的背心儿')
    q.put('粉红色的裤子')
    q.put('欧文的各种设备')
    print(q.get())
    print(q.get())
    print(q.get())
    q.task_done()
    q.task_done()
    q.task_done()
    q.join()
    

    欧文的各种设备
    粉红色的裤子
    粉红色的背心儿

    按照优先级

    q = queue.PriorityQueue() # 可以根据优先级取数据
    # 通常这个元组的第一个值是int类型
    q.put((50,'ccc'))
    q.put((80,'bbb'))
    q.put((1,'aaa'))
    print(q.get())
    print(q.get())
    print(q.get())
    q.task_done()
    q.task_done()
    q.task_done()
    q.join()
    

    (1, 'aaa')
    (50, 'ccc')
    (80, 'bbb')

    线程定时器

    就是定时多久开启一个线程,并且不会阻塞住。

    from threading import Thread,Timer
    import time
    
    
    def task():
        print('线程执行了')
        time.sleep(2)
        print('线程结束了')
    
    
    t = Timer(4,task) # 过了4s后开启了一个线程
    t.start()
    print('qweqweqwe')
    
    

    qweqweqwe
    线程执行了
    线程结束了

    这里打印qweqweqwe没有被阻塞,而是直接就打印了,并没有等待4秒,因为不会阻塞,

    这也是为什么有这个方法,而不用time.sleep的原因,因为sleep会阻塞住。

    进程池和线程池

    为什么要有进程池?进程池的概念。

    在程序实际处理问题过程中,忙时会有成千上万的任务需要被执行,闲时可能只有零星任务。那么在成千上万个任务需要被执行的时候,我们就需要去创建成千上万个进程么?首先,创建进程需要消耗时间,销毁进程也需要消耗时间。第二即便开启了成千上万的进程,操作系统也不能让他们同时执行,这样反而会影响程序的效率。因此我们不能无限制的根据任务开启或者结束进程。那么我们要怎么做呢?

    在这里,要给大家介绍一个进程池的概念,定义一个池子,在里面放上固定数量的进程,有需求来了,就拿一个池中的进程来处理任务,等到处理完毕,进程并不关闭,而是将进程再放回进程池中继续等待任务。如果有很多任务需要执行,池中的进程数量不够,任务就要等待之前的进程执行任务完毕归来,拿到空闲进程才能继续执行。也就是说,池中进程的数量是固定的,那么同一时间最多有固定数量的进程在运行。这样不会增加操作系统的调度难度,还节省了开闭进程的时间,也一定程度上能够实现并发效果

    线程池也一样。

    同步和异步的区别

    同步: 提交了一个任务,必须等任务执行完了(拿到返回值),才能执行下一行代码

    异步: 提交了一个任务,不要等执行完了,可以直接执行下一行代码.

    from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor
    from threading import currentThread
    from multiprocessing import current_process
    import time
    
    def task(i):
        print(f'{currentThread().name} 在执行任务 {i}')
        # print(f'进程 {current_process().name} 在执行任务 {i}')
        time.sleep(1)
        return i**2
    
    if __name__ == '__main__':
        pool = ThreadPoolExecutor(4) # 池子里只有4个线程
        # pool = ProcessPoolExecutor(4) # 池子里只有4个线程
        fu_list = []
        for i in range(20):
            # pool.submit(task,i) # task任务要做20次,4个线程负责做这个事
            future = pool.submit(task,i) # task任务要做20次,4个进程负责做这个事
            print(future.result()) # 如果没有结果一直等待拿到结果,导致了所有的任务都在串行
            #fu_list.append(future)
        #pool.shutdown() # 关闭了池的入口,会等待所有的任务执行完,结束阻塞.
        #for fu in fu_list:
           #print(fu.result())
    
    

    ThreadPoolExecutor-0_0 在执行任务 0
    0
    ThreadPoolExecutor-0_0 在执行任务 1
    1
    ThreadPoolExecutor-0_1 在执行任务 2
    4
    ThreadPoolExecutor-0_0 在执行任务 3
    9
    ThreadPoolExecutor-0_2 在执行任务 4
    16
    ThreadPoolExecutor-0_1 在执行任务 5
    25
    ThreadPoolExecutor-0_3 在执行任务 6
    36
    ThreadPoolExecutor-0_0 在执行任务 7
    49
    ThreadPoolExecutor-0_2 在执行任务 8
    64
    ThreadPoolExecutor-0_1 在执行任务 9
    81
    ThreadPoolExecutor-0_3 在执行任务 10
    100
    ThreadPoolExecutor-0_0 在执行任务 11
    121
    ThreadPoolExecutor-0_2 在执行任务 12
    144
    ThreadPoolExecutor-0_1 在执行任务 13
    169
    ThreadPoolExecutor-0_3 在执行任务 14
    196
    ThreadPoolExecutor-0_0 在执行任务 15
    225
    ThreadPoolExecutor-0_2 在执行任务 16
    256
    ThreadPoolExecutor-0_1 在执行任务 17
    289
    ThreadPoolExecutor-0_3 在执行任务 18
    324
    ThreadPoolExecutor-0_0 在执行任务 19
    361

    这就是同步了,因为你打印一定要等到他拿到这个result才能继续。

    因此,改良了一下

    '''
    进程池线程池:
        池的功能限制进程数或线程数.
        什么时候限制?
        当并发的任务数量远远大于计算机所能承受的范围,即无法一次性开启过多的任务数量
        我就应该考虑去限制我进程数或线程数,从保证服务器不崩.
    
    
    '''
    
    
    from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor
    from threading import currentThread
    from multiprocessing import current_process
    import time
    
    def task(i):
        print(f'{currentThread().name} 在执行任务 {i}')
        # print(f'进程 {current_process().name} 在执行任务 {i}')
        time.sleep(1)
        return i**2
    
    if __name__ == '__main__':
        pool = ThreadPoolExecutor(4) # 池子里只有4个线程
        # pool = ProcessPoolExecutor(4) # 池子里只有4个线程
        fu_list = []
        for i in range(20):
            # pool.submit(task,i) # task任务要做20次,4个线程负责做这个事
            future = pool.submit(task,i) # task任务要做20次,4个进程负责做这个事
            # print(future.result()) # 如果没有结果一直等待拿到结果,导致了所有的任务都在串行
            fu_list.append(future)
        pool.shutdown() # 关闭了池的入口,会等待所有的任务执行完,结束阻塞.
        for fu in fu_list:
            print(fu.result())
    
    
    
    

    ThreadPoolExecutor-0_0 在执行任务 0
    ThreadPoolExecutor-0_1 在执行任务 1
    ThreadPoolExecutor-0_2 在执行任务 2
    ThreadPoolExecutor-0_3 在执行任务 3
    ThreadPoolExecutor-0_2 在执行任务 4
    ThreadPoolExecutor-0_0 在执行任务 5
    ThreadPoolExecutor-0_1 在执行任务 6
    ThreadPoolExecutor-0_3 在执行任务 7
    ThreadPoolExecutor-0_0 在执行任务 8
    ThreadPoolExecutor-0_2 在执行任务 9
    ThreadPoolExecutor-0_1 在执行任务 10
    ThreadPoolExecutor-0_3 在执行任务 11
    ThreadPoolExecutor-0_1 在执行任务 12
    ThreadPoolExecutor-0_0 在执行任务 13
    ThreadPoolExecutor-0_2 在执行任务 14
    ThreadPoolExecutor-0_3 在执行任务 15
    ThreadPoolExecutor-0_1 在执行任务 16
    ThreadPoolExecutor-0_2 在执行任务 17
    ThreadPoolExecutor-0_0 在执行任务 18
    ThreadPoolExecutor-0_3 在执行任务 19
    0
    1
    4
    9
    16
    25
    36
    49
    64
    81
    100
    121
    144
    169
    196
    225
    256
    289
    324
    361

    把所有的future都放进列表,然后列表一起拿结果。但是这样消耗的时间还是太多了。

    于是就有了一个叫做回调函数的东西。

    '''
    进程池线程池:
        池的功能限制进程数或线程数.
        什么时候限制?
        当并发的任务数量远远大于计算机所能承受的范围,即无法一次性开启过多的任务数量
        我就应该考虑去限制我进程数或线程数,从保证服务器不崩.
    
    
    理解为提交任务的两种方式
    同步: 提交了一个任务,必须等任务执行完了(拿到返回值),才能执行下一行代码,
    
    
    异步: 提交了一个任务,不要等执行完了,可以直接执行下一行代码.
    
    
    '''
    
    
    from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor
    from threading import currentThread
    from multiprocessing import current_process
    import time
    
    def task(i):
        print(f'{currentThread().name} 在执行任务 {i}')
        # print(f'进程 {current_process().name} 在执行任务 {i}')
        time.sleep(1)
        return i**2
    
    
    def parse(future):
        # 处理拿到的结果
        print(future.result())
    
    
    
    if __name__ == '__main__':
        pool = ThreadPoolExecutor(4) # 池子里只有4个线程
        # pool = ProcessPoolExecutor(4) # 池子里只有4个线程
        fu_list = []
        for i in range(20):#4
            # pool.submit(task,i) # task任务要做20次,4个线程负责做这个事
            future = pool.submit(task,i) # task任务要做20次,4个进程负责做这个事
            future.add_done_callback(parse)
            # 为当前任务绑定了一个函数,在当前任务执行结束的时候会触发这个函数,
            # 会把future对象作为参数传给函数
            # 这个称之为回调函数,处理完了回来就调用这个函数.
            # print(future.result()) # 如果没有结果一直等待拿到结果,导致了所有的任务都在串行
    
        # pool.shutdown() # 关闭了池的入口,会等待所有的任务执行完,结束阻塞.
        # for fu in fu_list:
        #     print(fu.result())
    

    ThreadPoolExecutor-0_0 在执行任务 0
    ThreadPoolExecutor-0_1 在执行任务 1
    ThreadPoolExecutor-0_2 在执行任务 2
    ThreadPoolExecutor-0_3 在执行任务 3
    0
    ThreadPoolExecutor-0_0 在执行任务 4
    1
    ThreadPoolExecutor-0_1 在执行任务 5
    4
    ThreadPoolExecutor-0_2 在执行任务 6
    9
    ThreadPoolExecutor-0_3 在执行任务 7
    16
    ThreadPoolExecutor-0_0 在执行任务 8
    25
    ThreadPoolExecutor-0_1 在执行任务 9
    36
    ThreadPoolExecutor-0_2 在执行任务 10
    49
    ThreadPoolExecutor-0_3 在执行任务 11
    64
    ThreadPoolExecutor-0_0 在执行任务 12
    100
    81
    ThreadPoolExecutor-0_1 在执行任务 13
    ThreadPoolExecutor-0_2 在执行任务 14
    121
    ThreadPoolExecutor-0_3 在执行任务 15
    144
    ThreadPoolExecutor-0_0 在执行任务 16
    196
    169
    ThreadPoolExecutor-0_2 在执行任务 17
    ThreadPoolExecutor-0_1 在执行任务 18
    225
    ThreadPoolExecutor-0_3 在执行任务 19
    256
    324
    289
    361

    这才是正确操作。

  • 相关阅读:
    初识线段树
    win7下vc6.0打开文件未响应的解决方法
    SQL 2008安装
    20200730 Div.2模拟赛题解
    20190928 Div3模拟赛题解
    Codeforces Round #664 (Div. 2) 题解
    CSP2019回忆录
    [SHOI2014]三叉神经树(加强版)题解
    Linux 下修改Swap区设置
    LoadRunner监控Linux与Windows方法
  • 原文地址:https://www.cnblogs.com/chanyuli/p/11552902.html
Copyright © 2020-2023  润新知