Python中ThreadPoolExecutor的使用

 线程(英语: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参数,以达到最佳性能。

  • 29
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Python,可以使用`concurrent.futures`模块的`ThreadPoolExecutor`类来进行多线程处理。在使用`ThreadPoolExecutor`调用WebSocket时,可以通过`websocket`库提供的异步方法来实现。 下面是一个简单的例子,假设我们要使用`ThreadPoolExecutor`类来调用WebSocket,代码如下: ```python import websocket import concurrent.futures def on_message(ws, message): print(message) def on_error(ws, error): print(error) def on_close(ws): print("### closed ###") def on_open(ws): def run(*args): ws.send("Hello, world!") time.sleep(1) ws.close() print("thread terminating...") executor.submit(run) if __name__ == "__main__": websocket.enableTrace(True) ws = websocket.WebSocketApp("ws://echo.websocket.org/", on_message=on_message, on_error=on_error, on_close=on_close) ws.on_open = on_open with concurrent.futures.ThreadPoolExecutor() as executor: executor.submit(ws.run_forever) ``` 上面的代码,我们首先导入了`websocket`和`concurrent.futures`模块,然后定义了一些回调函数,包括接收到消息时的回调函数`on_message`、发生错误时的回调函数`on_error`、关闭连接时的回调函数`on_close`和建立连接时的回调函数`on_open`。在`on_open`回调函数,我们创建了一个新线程,并将其提交给线程池的线程执行。 最后,我们通过`with concurrent.futures.ThreadPoolExecutor() as executor:`语句块来创建一个线程池对象,并使用`executor.submit(ws.run_forever)`语句将WebSocket连接的运行方法提交给线程池。这样就可以实现多线程处理WebSocket了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值