Python 线程池(让初学者简单易懂)

线程池(thread pool)

        一种线程使用模式。线程过多会带来调度开销,进而影响缓存局部性和整体性能。而线程池维护着多个线程,等待着监督管理者分配可并发执行的任务。

        这避免了在处理短时间任务时创建与销毁线程的代价。线程池不仅能够保证内核的充分利用,还能防止过分调度。可用线程数量应该取决于可用的并发处理器、处理器内核、内存、网络sockets等的数量。 例如,线程数一般取cpu数量+2比较合适,线程数过多会导致额外的线程切换开销。

        创建线程对象的期间会损耗时间,尤其是在需要开辟大量线程对象的时候会发生性能下降的情况。那么我们能否让程序创建一定数量的线程对象,并且在执行完某一个任务后不会被解释器销毁,下一个任务重复使用之前所创建的线程对象。

像这种需要创建大量线程对象的场景推荐使用线程池。

import time
from concurrent.futures import ThreadPoolExecutor, as_completed, wait
import requests


def get_image(url):
    """
        requests.get(url)   方法获取URL的响应
        response.content    获取响应的网页内容
    """
    response = requests.get(url).content
    # 提取文件名
    file_name = url.rsplit('/')[-1]
    with open(file_name, 'wb') as f:
        f.write(response)
        time.sleep(1)
        print("下载完成...")
    return response


# 创建线程池对象(最大线程为2)
pool_1 = ThreadPoolExecutor(max_workers=2)

url_list = [
    'http://pic.bizhi360.com/bbpic/98/10798.jpg',
    'http://pic.bizhi360.com/bbpic/92/10792.jpg',
    'http://pic.bizhi360.com/bbpic/86/10386.jpg'
]

all_task = [pool_1.submit(get_image, img_url) for img_url in url_list]
# 运行线程池后
# wait()让主线程阻塞,等待所有任务完成后接着运行
wait(all_task)
print("主线程结束运行...")

# 关闭线程池
pool_1.shutdown()
 # 方式一:
 for img_url in url_list:
     # submit()用于提交任务,并且返回类型为future类型的值
     future = pool_1.submit(get_image, img_url)
     # result()用于获取所有任务的返回值,并且在所有任务完成后一起返回
     print(future.result())

# 方式二
# 将所有任务的返回值存储在 列表 all_task中
 all_task = [pool_1.submit(get_image, img_url) for img_url in url_list]

 as_completed(all_task)  # 返回一个迭代器
 # 获取所有返回值,然后一次性提交
 for future in as_completed(all_task):
     print(future.result())
# 方式三
# map可以提交任务,当前任务的参数可以使用迭代对象进行传递
 for res in pool_1.map(get_image, url_list):
     pass

比喻环节(更好理解)

大学生需要去水房接水

当有一个人接水时,就要使用一个水龙头,多一个人时又要使用一个水龙头

那么我们预先创建一定数量的线程(五个水龙头),当六个人来水房用水时,先让五个人使用,另一个人等待,有人用完后离开,水龙头空闲(线程返回线程池等待下一个任务),等待的人上前使用。

线程池的优缺点

优点:

  • 重用线程,避免了频繁创建和销毁线程的开销。(重复开关水龙头,1000人挨个使用一个水龙头,会坏掉的)
  • 通过限制线程池的大小,可以避免过多的线程竞争资源,从而提高程序的稳定性。(防止等的人太多,都想用然后打起来)
  • 线程池可以方便地管理线程的生命周期,简化了线程的同步和通信。(哪个水龙头坏了修哪个,不用直接修主水管)

缺点:

  • 如果线程池中的线程数量设置不当,可能会导致资源浪费或性能瓶颈。(1000个水龙头没必要【浪费】,但三个水龙头又不够10个人用【性能瓶颈】)
  • 线程池的实现和管理相对多线程来说更复杂一些。(注意线程池的线程执行的是相同的任务,而多线程是一个程序创建多个线程执行不同的任务)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值