Loading

池和异步回调机制

【1】概念

  • 池是用来保证计算机硬件安全的情况下,最大限度的利用计算机资源,降低了程序的运行效率,但是保证了计算机硬件的安全

  • 池(Pool)的概念在计算机科学和软件工程中常被用于资源管理,尤其是在多线程或并发编程中。池是一种管理和优化资源分配的机制,它事先分配一定数量的资源(如线程、数据库连接、对象等),并在需要时重用这些资源,而不是每次都创建和销毁。

【2】类型

  1. 线程池(Thread Pool):线程池维护一组预先创建的线程,这些线程可以执行多个任务。当一个任务提交给线程池时,线程池会尝试使用一个空闲的线程来执行该任务。使用线程池可以减少因为频繁创建和销毁线程而产生的开销,提高响应速度,同时限制并发线程的数量,防止资源过度使用。
  2. 进程池(Process Pool):与线程池类似,进程池维护一组预先创建的进程。这在并行处理和分布式计算中非常有用,尤其是当每个任务需要大量计算资源时。
  3. 数据库连接池(Database Connection Pool):在数据库应用中,建立数据库连接是一个资源密集和时间消耗的操作。数据库连接池预先创建一定数量的数据库连接,并在需要时重用这些连接,提高了数据库操作的效率。
  4. 对象池(Object Pool):对象池用于管理对象的创建和分配。它维护一组已经初始化的对象。当需要一个新对象时,可以从池中获取,使用后再放回池中,而不是销毁。

【3】优势

  • 提高性能:通过减少创建和销毁资源的次数,减少系统开销。
  • 资源复用:已分配的资源可以被多次重用,提高资源利用率。
  • 控制上限:限制同时活跃的资源数量,防止因过多资源同时使用而耗尽系统资源。

线程池

【1】导入方法

  • from concurrent.futures import ThreadPoolExecutor

【2】使用方法

  • 先实例化一个线程池对象t_pool = ThreadPoolExecutor(5)
  • 这里的参数可以自己填,不填的话,默认就是电脑cpu个数乘5
  • t_list = [t_pool.submit(task, i) for i in range(1, 51)]通过submit()方法向线程池中提交任务
  • submit(task, i)第一个参数是函数名,第二个参数是函数的参数
  • 通过result()方法可以得到线程池里的线程的返回值
  • shutdown()方法可以使线程池关闭,不再处理新的任务,但是会处理已经提交给线程池内部正在运行,以及在队列中还未运行的线程

【3】进房间洗脚例子

from concurrent.futures import ThreadPoolExecutor
import time


def task(i):
    print(f'客户{i}来到了房间洗脚')
    time.sleep(2)
    return f'客户{i}来洗脚啦'


if __name__ == '__main__':
    t_pool = ThreadPoolExecutor(5)

    t_list = [t_pool.submit(task, i) for i in range(1, 51)]
    t_pool.shutdown()
    for t in t_list:
        print(t.result())

  • 首先将任务添加到线程池,然后再关闭线程池,等待所有线程起来之后,最后再一起输出结果
  • 也可以使用with ThreadPoolExecutor(3) as p_pool:自动执行shutdown()方法

进程池

【1】导入方法

  • from concurrent.futures import ProcessPoolExecutor

【2】使用方法

  • 进程池的使用方法和线程池基本一致
  • 但是如果不给进程池传入参数时,默认值会是当前电脑cpu的个数

【3】池里面的进程或者线程是不会变的

  • 上面的线程池不太好说明
  • 但是进程池就可以很好的印证这一点
  • 还是一样的洗脚例子
from concurrent.futures import ProcessPoolExecutor
import os
import time


def task(i):
    pid = os.getpid()
    time.sleep(1)
    print(f'客户{i}进入房间洗脚----客户的手牌号为{pid}')


if __name__ == '__main__':
    p_pool = ProcessPoolExecutor(3)
    p_list = [p_pool.submit(task, i) for i in range(1, 21)]
  • 打印 出来观察结果,可以发现进程池里面的进程ID是不变的,永远都是那么几个

异步回调机制

【1】介绍

  • 异步回调机制是一种编程模式,它允许程序在执行长时间运行的任务时继续执行其他代码,并在这些长时间运行的任务完成后得到通知。
  • 结合上面的例子,我们想要拿到线程的返回值,但是拿到返回值就需要1秒的阻塞,用了异步回调函数之后,就可以实现线程的并发,等到拿到了函数的返回值,再调回来拿结果。

【2】异步回调的优势

  • 非阻塞行为:主程序可以继续执行其他任务,而不必等待长时间运行的任务完成。

  • 简化代码结构:回调机制允许我们将后续处理逻辑清晰地与长时间运行的任务分离。

  • 提高响应性:在用户界面或网络应用中,异步回调能够提高程序的响应性,因为主线程不会被长时间运行的任务阻塞。

  • 异步回调在现代编程中非常普遍,特别是在处理I/O操作(如文件读写、网络请求)或其他需要等待的任务时。

【3】例子

from concurrent.futures import ProcessPoolExecutor
import os
import time


def task(i):
    pid = os.getpid()
    time.sleep(2)
    print(f'客户{i}进入房间洗脚----客户的手牌号为{pid}')
    return f'客户{i}来洗脚啦'

def result(future):
    print(future.result())


if __name__ == '__main__':
    p_pool = ProcessPoolExecutor(3)
    p_list = [p_pool.submit(task, i).add_done_callback(result) for i in range(1, 11)]

  • add_done_callback()调用这个方法会自动将p_pool对象作为第一个参数传入,而这个对象就有一个result()方法可以拿到返回值
  • 定义了一个result函数,参数是future对象,也就是p_pool对象,函数内容就是输出p_pool对象的返回值,然后再将这个函数地址作为add_done_callback()的参数传入
posted @ 2024-01-20 18:43  HuangQiaoqi  阅读(10)  评论(0编辑  收藏  举报