线程(英语:thread)是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。在Unix System V及SunOS中也被称为轻量进程(lightweight processes),但轻量进程更多指内核线程(kernel thread),而把用户线程(user thread)称为线程。
线程是独立调度和分派的基本单位。同一进程中的多条线程将共享该进程中的全部系统资源,如虚拟地址空间,文件描述符和信号处理等等。但同一进程中的多个线程有各自的调用栈(call stack),自己的寄存器环境(register context),自己的线程本地存储(thread-local storage)。一个进程可以有很多线程,每条线程并行执行不同的任务。
线程池是一种利用池化技术思想来实现的线程管理技术,主要是为了复用线程、便利地管理线程和任务、并将线程的创建和任务的执行解耦开来。
ThreadPoolExecutor在Java中是用于管理线程池的工具类,它提供了多种方法来创建、配置和管理线程池。ThreadPoolExecutor的主要目的是提高线程的复用性,减少线程创建和销毁的开销。
ThreadPoolExecutor的主要构造函数有:
1. ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue):
- corePoolSize:核心线程数,即线程池中始终存在的线程数。
- maximumPoolSize:最大线程数,即线程池中允许的最大线程数。
- keepAliveTime:空闲线程的存活时间,当线程池中的线程数超过corePoolSize时,多余的线程在空闲时间超过keepAliveTime后会被销毁。
- unit:keepAliveTime的时间单位。
- workQueue:任务队列,用于存放待执行的任务。2. ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory):
- threadFactory:线程工厂,用于创建新线程。3. ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler):
- handler:任务拒绝处理器,当任务无法执行时(例如线程池已关闭或任务队列已满),如何处理该任务。ThreadPoolExecutor的主要方法有:
1. execute(Runnable command):提交一个任务,该任务将在线程池中执行。如果线程池已关闭,该任务将被拒绝。
2. submit(Runnable task):提交一个任务,并返回一个Future对象,该对象表示任务的执行结果。如果线程池已关闭,该任务将被拒绝。
3. shutdown():启动线程池的关闭过程,不再接受新任务,但会执行已提交的任务。
4. shutdownNow():立即关闭线程池,不再执行任何任务,并返回尚未执行的任务列表。
5. isShutdown():检查线程池是否已关闭。
6. isTerminated():检查线程池中的所有任务是否已执行完成。
7. awaitTermination(long timeout, TimeUnit unit):等待线程池中的所有任务执行完成,直到超时或线程池关闭。
8. getPoolSize():获取线程池中的线程数。
9. getActiveCount():获取线程池中正在执行任务的线程数。
10. getCompletedTaskCount():获取线程池已完成的任务数。
11. getTaskCount():获取线程池已提交的任务数。
12. getLargestPoolSize():获取线程池中曾经同时存在的最大线程数。
13. getQueue():获取线程池中的任务队列。
14. getRejectedExecutionHandler():获取任务拒绝处理器。
15. setRejectedExecutionHandler(RejectedExecutionHandler handler):设置任务拒绝处理器。
ThreadPoolExecutor是一个线程池实现,它提供了多种方法来创建、配置和管理线程池,从而提高线程的复用性,减少线程创建和销毁的开销。
Python中的ThreadPoolExecutor来自于concurrent.futures模块,它是Python标准库的一部分,用于实现线程池。ThreadPoolExecutor允许你将任务提交到线程池中,从而异步执行任务,提高程序的执行效率。
ThreadPoolExecutor的主要构造函数有:
1. ThreadPoolExecutor(max_workers=None, thread_name_prefix='')
- max_workers:线程池中线程的数量。如果未指定或为None,将使用系统处理器的核心数。
- thread_name_prefix:为线程设置一个前缀,以便于区分。ThreadPoolExecutor的主要方法有:
1. submit(fn, *args, **kwargs)
- 提交一个可调用对象fn到线程池,并返回一个Future对象。Future对象表示任务的执行结果。2. map(fn, *iterables, timeout=None, chunksize=1)
- 对多个可迭代对象进行映射,将fn应用到它们的元素上,并返回一个生成器,用于获取结果。3. shutdown(wait=True)
- 关闭线程池,不再接受新的任务,但会完成已提交的任务。如果wait为True,将等待所有任务完成。4. terminate()
- 立即关闭线程池,不再执行任何任务。5. join()
- 等待线程池中的所有线程完成。6. is_shutdown()
- 检查线程池是否已关闭。7. is_terminated()
- 检查线程池中的所有任务是否已执行完成。
使用ThreadPoolExecutor可以方便地实现线程池,提高程序的执行效率。下面是一个简单的示例:
import concurrent.futures
import time
def some_function(n):
print(f"Function {n} started")
time.sleep(n)
print(f"Function {n} finished")
return n
with concurrent.futures.ThreadPoolExecutor(max_workers=3) as executor:
futures = [executor.submit(some_function, i) for i in range(5)]
for future in concurrent.futures.as_completed(futures):
result = future.result()
print(f"Function {result} returned {result}")
在这个示例中,我们创建了一个ThreadPoolExecutor,并提交了5个任务到线程池。这些任务会并发执行,而不是顺序执行。通过as_completed()函数,我们可以获取已完成的任务的结果。
在实际情况中,使用线程池,可以提高代码效率,下面使用ThreadPoolExecutor结合爬虫进行演示。
from concurrent.futures import ThreadPoolExecutor
import requests
from bs4 import BeautifulSoup
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) '
'AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.64 Safari/537.36'
}
def down_novel(url):
# 发送请求获取网页内容
html = requests.get(url, headers=headers).text
# 解析网页内容
soup = BeautifulSoup(html, 'lxml')
# 获取小说标题
title_obj = soup.find('h1', class_='wap_none')
# 获取小说内容
con_obj = soup.find('div', id='chaptercontent')
if title_obj and con_obj:
title = title_obj.get_text()
con = con_obj.get_text()
with open(f'txt/{title}.txt', 'w', encoding='utf-8') as f:
print(f'正在下载: {title}')
f.write(con)
def main():
# url = 'https://www.bqgka.com/book/159995/'
url = input('请输入小说地址:')
# 调用函数下载小说
url = url
html = requests.get(url, headers=headers).text
soup = BeautifulSoup(html, 'lxml')
items = soup.find('div', class_='listmain').find_all('a')
urls = []
for item in items:
href = item['href']
if href != 'javascript:dd_show()':
urls.append('https://www.bqgka.com' + href)
# 创建线程池
with ThreadPoolExecutor(max_workers=10) as executor:
for url in urls:
executor.submit(down_novel, url)
if __name__ == '__main__':
main()
在此代码中,我们利用ThreadPoolExecutor创建了大小为10的线程池,通过for循环将任务分发给创建的10个线程,用于并发地下载网络小说。
需要注意的是,使用线程池可以提高任务并发执行的速度,但是也会增加内存占用和CPU负载。因此,在使用线程池时,需要根据实际情况调整max_workers
参数,以达到最佳性能。