python 多线程 加速处理列表数据

背景

最近使用大模型进行推理时,首先将大模型 api 部署,然后借助于 request库,发送请求。

在之前写同步的请求,必须等到上一次request响应的结果回来后,才能发送下一次请求,这样导致速度非常慢。

由于大模型部署支持并发,故打算采用多线程方式,让大模型快速处理。

简介

  • 多线程

多线程示例代码

python 复制代码
import concurrent
from concurrent.futures import ThreadPoolExecutor  
from tqdm import tqdm  
import time  

start = time.time()
# 假设我们有一个URL列表,这里用占位符代替  
urls = [i for i in range(25)]  

# 模拟发送网络请求  
def send_request(url):
    print(f"发送请求 {url}")
    time.sleep(1)  # 模拟网络延迟
    print(f"收到请求 {url} 的响应")
    return url

# 使用ThreadPoolExecutor创建线程池,并限制线程数为 max_workers
with ThreadPoolExecutor(max_workers=5) as executor:  
    # 使用executor的map方法将urls列表中的每个URL映射到send_request函数  
    # 这会自动将任务分配给线程池中的线程,而且 results_iterator 收集到的返回值的结果
    results_iterator = executor.map(send_request, urls)
    
end = time.time()

print(f"总共耗时 {end - start} 秒")
python 复制代码
print(list(results_iterator))

results_iterator 收集到的返回值是有序的

多线程的运行结果如下所示:

bash 复制代码
发送请求 0
发送请求 1
发送请求 2
发送请求 3
发送请求 4
收到请求 0 的响应收到请求 3 的响应
发送请求 5
收到请求 4 的响应
发送请求 6

发送请求 7
收到请求 1 的响应
发送请求 8
收到请求 2 的响应
发送请求 9
收到请求 5 的响应
发送请求 10
收到请求 6 的响应
发送请求 11
收到请求 7 的响应
发送请求 12
收到请求 9 的响应
发送请求 13
收到请求 8 的响应
发送请求 14
...
收到请求 24 的响应
收到请求 22 的响应

总共耗时 5.021236896514893 秒

关于 核心数选取多少:

在Python中,多线程的性能并不总是随着线程数的增加而线性提升,尤其是在执行CPU密集型任务时。这是因为Python的全局解释器锁(GIL)限制了一次只能有一个线程执行Python字节码。所以,即使你的机器有多个CPU核心,Python的多线程在并行执行CPU密集型任务时可能并不会充分利用所有的核心。

然而,如果你的线程主要执行I/O操作(如网络请求、文件读写等),那么多线程可以有效地利用等待时间,从而提高程序的总体效率。在这种情况下,线程数可以超过CPU核心数,因为线程会在等待I/O操作时自动切换。

对于CPU密集型任务,如果你想要充分利用多核CPU的性能,更好的选择是使用多进程(multiprocessing)而不是多线程。Python的multiprocessing库可以创建多个进程,每个进程都有自己的Python解释器,从而可以并行执行CPU密集型任务。

至于具体应该设置多少线程或进程,这取决于你的具体需求和机器的配置。一般来说,对于I/O密集型任务,线程数可以设置为略多于CPU核心数,以便在等待I/O时充分利用CPU。对于CPU密集型任务,进程数可以设置为等于或略少于CPU核心数,以避免过多的上下文切换开销。但请注意,这只是一个一般性的建议,具体的最佳值可能需要通过实验来确定。

对比 不使用多线程

python 复制代码
start = time.time()
# 假设我们有一个URL列表,这里用占位符代替  
urls = [i for i in range(25)]  

# 定义一个函数来发送网络请求  
def send_request(url):
    print(f"发送请求 {url}")
    time.sleep(1)  # 模拟网络延迟
    print(f"收到请求 {url} 的响应")
    return url

ans = []
for url in urls:
    ans.append(send_request(url))
    
end = time.time()

print(f"总共耗时 {end - start} 秒")
bash 复制代码
发送请求 0
收到请求 0 的响应
发送请求 1
收到请求 1 的响应
发送请求 2
收到请求 2 的响应
发送请求 3
收到请求 3 的响应
发送请求 4
收到请求 4 的响应
发送请求 5
收到请求 5 的响应
发送请求 6
收到请求 6 的响应
发送请求 7
收到请求 7 的响应
发送请求 8
收到请求 8 的响应
发送请求 9
收到请求 9 的响应
发送请求 10
收到请求 10 的响应
发送请求 11
收到请求 11 的响应
发送请求 12
...
收到请求 23 的响应
发送请求 24
收到请求 24 的响应
总共耗时 25.100407123565674 秒

如果不使用多线程的,必须收到上一次请求的响应,才能发送下一个请求;总共耗时25秒,而多线程只需要5秒;

相关推荐
随心点儿21 分钟前
使用python 将多个docx文件合并为一个word
开发语言·python·多个word合并为一个
不学无术の码农25 分钟前
《Effective Python》第十三章 测试与调试——使用 Mock 测试具有复杂依赖的代码
开发语言·python
tomcsdn3130 分钟前
SMTPman,smtp的端口号是多少全面解析配置
服务器·开发语言·php·smtp·邮件营销·域名邮箱·邮件服务器
sleepybear111331 分钟前
在Ubuntu上从零开始编译并运行Home Assistant源码并集成HACS与小米开源的Ha Xiaomi Home
python·智能家居·小米·home assistant·米家·ha xiaomi home
EnigmaCoder35 分钟前
Java多线程:核心技术与实战指南
java·开发语言
纪伊路上盛名在37 分钟前
(鱼书)深度学习入门1:python入门
人工智能·python·深度学习
夏末蝉未鸣011 小时前
python transformers笔记(TrainingArguments类)
python·自然语言处理·transformer
德育处主任Pro1 小时前
「py数据分析」04如何将 Python 爬取的数据保存为 CSV 文件
数据库·python·数据分析
咸鱼鲸1 小时前
【PyTorch】PyTorch中数据准备工作(AI生成)
人工智能·pytorch·python
遇见你很高兴1 小时前
Pycharm中体验通义灵码来AI辅助编程
python