第11天续,Python并发编程之线程池/进程池

简介: @(python)目录引言Executor和Future使用submit来操作线程池/进程池add_done_callback实现回调函数引言Python标准库为我们提供了threading和multiprocessing模块编写相应的多线程/多进程代码,但是当项目达到一定的规模,频繁创建/销毁进程或者线程是非常消耗资源的,这个时候我们就要编写自己的线程池/进程池,以空间换时间。

@(python)

目录

引言
Executor和Future
使用submit来操作线程池/进程池
add_done_callback实现回调函数

引言

Python标准库为我们提供了threadingmultiprocessing模块编写相应的多线程/多进程代码,但是当项目达到一定的规模,频繁创建/销毁进程或者线程是非常消耗资源的,这个时候我们就要编写自己的线程池/进程池,以空间换时间。但从Python3.2开始,标准库为我们提供了concurrent.futures模块,它提供了ThreadPoolExecutorProcessPoolExecutor两个类,实现了对threadingmultiprocessing的进一步抽象,对编写线程池/进程池提供了直接的支持。

Executor和Future

concurrent.futures模块的基础是ExectuorExecutor是一个抽象类,它不能被直接使用。但是它提供的两个子类ThreadPoolExecutorProcessPoolExecutor却是非常有用,顾名思义两者分别被用来创建线程池和进程池的代码。我们可以将相应的tasks直接放入线程池/进程池,不需要维护Queue来操心死锁的问题,线程池/进程池会自动帮我们调度。

Future这个概念相信有java和nodejs下编程经验的朋友肯定不陌生了,你可以把它理解为一个在未来完成的操作,这是异步编程的基础,传统编程模式下比如我们操作queue.get的时候,在等待返回结果之前会产生阻塞,cpu不能让出来做其他事情,而Future的引入帮助我们在等待的这段时间可以完成其他的操作。

p.s:如果你依然在坚守Python2.x,请先安装futures模块。pip install futures

使用submit来操作线程池/进程池

我们先通过下面这段代码来了解一下线程池的概念:

# example1.py 
from concurrent.futures import ThreadPoolExecutor 
import time 
def return_future_result(message): 
    time.sleep(2) 
    return message 
pool = ThreadPoolExecutor(max_workers=2)  # 创建一个最大可容纳2个task的线程池 
future1 = pool.submit(return_future_result, ("hello"))  # 往线程池里面加入一个task 
future2 = pool.submit(return_future_result, ("world"))  # 往线程池里面加入一个task 
print(future1.done())  # 判断task1是否结束 
time.sleep(3) 
print(future2.done())  # 判断task2是否结束 
print(future1.result())  # 查看task1返回的结果 
print(future2.result())  # 查看task2返回的结果 

执行结果:

False 
True 
hello 
world 

解析:我们根据运行结果来分析一下。我们使用submit方法来往线程池中加入一个task,submit返回一个Future对象,对于Future对象可以简单地理解为一个在未来完成的操作。在第一个print语句中很明显因为time.sleep(2)的原因我们的future1没有完成,因为我们使用time.sleep(3)暂停了主线程,所以到第二个print语句的时候我们线程池里的任务都已经全部结束。

上面的代码我们也可以改写为进程池形式,api和线程池如出一辙,我就不罗嗦了。

# example2.py 
from concurrent.futures import ProcessPoolExecutor 
import time 
def return_future_result(message): 
    time.sleep(2) 
    return message 
pool = ProcessPoolExecutor(max_workers=2) 
future1 = pool.submit(return_future_result, ("hello")) 
future2 = pool.submit(return_future_result, ("world")) 
print(future1.done()) 
time.sleep(3) 
print(future2.done()) 
print(future1.result()) 
print(future2.result()) 

参考此篇博客

add_done_callback实现回调函数

from concurrent.futures import ThreadPoolExecutor
import requests

def task(url):
    response = requests.get(url)

    if response.status_code == 200:
        return response

def download(futures):
    response = futures.result()  #会得到一个返回值,这个返回值就是task函数的返回值
    content = response.text
    tmp_list = response.url.split("/")
    filename = tmp_list[len(tmp_list)-1]
    print("正在下载:%s" %response.url)
    with open(filename,"w",encoding="utf-8") as f:
        f.write("%s\n%s" %(response.url,content))
        print("下载完成")

url_list = [
    "http://www.cnblogs.com/wupeiqi/articles/5713330.html",
    "http://blog.csdn.net/anzhsoft/article/details/19563091",
    "http://blog.csdn.net/anzhsoft/article/details/19570187"
]

thread_pool = ThreadPoolExecutor(max_workers=2) #生一个线程池对象,最大线程数为2个

for url in url_list:
    futures = thread_pool.submit(task,url)  #会得到一个Future对象
    #回调函数,会将futures本身当作参数传给download函数
    futures.add_done_callback(download)
相关文章
|
4天前
|
数据挖掘 程序员 调度
探索Python的并发编程:线程与进程的实战应用
【10月更文挑战第4天】 本文深入探讨了Python中实现并发编程的两种主要方式——线程和进程,通过对比分析它们的特点、适用场景以及在实际编程中的应用,为读者提供清晰的指导。同时,文章还介绍了一些高级并发模型如协程,并给出了性能优化的建议。
15 3
|
1天前
|
存储 Python
Python中的多进程通信实践指南
Python中的多进程通信实践指南
7 0
|
9天前
|
数据采集 消息中间件 Python
Python爬虫-进程间通信
Python爬虫-进程间通信
10 0
|
18天前
|
数据采集 Linux 调度
Python之多线程与多进程
Python之多线程与多进程
23 0
|
23天前
|
存储 算法 Java
关于python3的一些理解(装饰器、垃圾回收、进程线程协程、全局解释器锁等)
该文章深入探讨了Python3中的多个重要概念,包括装饰器的工作原理、垃圾回收机制、进程与线程的区别及全局解释器锁(GIL)的影响等,并提供了详细的解释与示例代码。
17 0
|
23天前
|
调度 Python
python3多进程实战(python3经典编程案例)
该文章提供了Python3中使用多进程的实战案例,展示了如何通过Python的标准库`multiprocessing`来创建和管理进程,以实现并发任务的执行。
46 0
|
3月前
|
安全 Python
告别低效编程!Python线程与进程并发技术详解,让你的代码飞起来!
【7月更文挑战第9天】Python并发编程提升效率:**理解并发与并行,线程借助`threading`模块处理IO密集型任务,受限于GIL;进程用`multiprocessing`实现并行,绕过GIL限制。示例展示线程和进程创建及同步。选择合适模型,注意线程安全,利用多核,优化性能,实现高效并发编程。
64 3
|
3月前
|
安全 数据安全/隐私保护 数据中心
Python并发编程大挑战:线程安全VS进程隔离,你的选择影响深远!
【7月更文挑战第9天】Python并发:线程共享内存,高效但需处理线程安全(GIL限制并发),适合IO密集型;进程独立内存,安全但通信复杂,适合CPU密集型。使用`threading.Lock`保证线程安全,`multiprocessing.Queue`实现进程间通信。选择取决于任务性质和性能需求。
84 1
|
3月前
|
Python
解锁Python并发新世界:线程与进程的并行艺术,让你的应用性能翻倍!
【7月更文挑战第9天】并发编程**是同时执行多个任务的技术,提升程序效率。Python的**threading**模块支持多线程,适合IO密集型任务,但受GIL限制。**multiprocessing**模块允许多进程并行,绕过GIL,适用于CPU密集型任务。例如,计算平方和,多线程版本使用`threading`分割工作并同步结果;多进程版本利用`multiprocessing.Pool`分块计算再合并。正确选择能优化应用性能。
31 1
|
23天前
|
负载均衡 Java 调度
探索Python的并发编程:线程与进程的比较与应用
本文旨在深入探讨Python中的并发编程,重点比较线程与进程的异同、适用场景及实现方法。通过分析GIL对线程并发的影响,以及进程间通信的成本,我们将揭示何时选择线程或进程更为合理。同时,文章将提供实用的代码示例,帮助读者更好地理解并运用这些概念,以提升多任务处理的效率和性能。
45 3