浅谈一下python线程池简单应用

一、线程池简介

传统多线程方案会使用“即时创建,即时销毁”的策略。尽管与创建进程相比,创建线程的时间已经大大的缩短,但是如果提交给线程的任务时执行时间较短,而且执行次数及其频繁,那么服务器将处于不停的创建线程,销毁线程的状态。

一个线程的运行时间可以分为三部分:线程的启动时间、线程体的运行时间和线程的销毁时间。

在多线程处理的情景中,如果线程不能被重用,就意味着每次线程运行都要经过启动、销毁和运行3个过程。这必然会增加系统相应的时间,减低了效率。

线程池在系统启动时即创建大量空闲的线程,程序只要将一个函数提交给线程池,线程池就会启动一个空闲的线程来执行它。

当该函数执行结束后,该线程并不会死亡,而是再次返回到线程池中变成空闲状态,等待执行下一个函数,因此能够避免多次创建线程,从而节省线程创建和销毁的开销,能带来更好的性能和稳定性。

此外,使用线程池可以有效地控制系统中并发线程的数量。当系统中包含有大量的并发线程时,会导致系统性能急剧下降,甚至导致Python解释器崩溃,而线程池的最大线程数参数可以控制系统中并发线程的数量不超过此数。

服务器CPU数有限,能够同时并发的线程数有限,并不是开得越多越好,以及线程切换时有开销的,如果线程切换过于频繁,反而会使性能降低。

线程池适用于:突发性大量请求或需要大量线程完成任务,但实际任务处理时间较短的场景

二、线程池在python中的应用

从python3.2开始,标准库提供了concurrent.futures模块,它提供了两个子类:ThreadPoolExecutor和ProcessPoolExecutor。其中ThreadPoolExecutor用于创建线程池,而ProcessPoolExecutor用于创建进程池。不仅可以自动调度线程,还可以做到:

  • 主线程可以获取某一个线程(或任务)的状态,以及返回值
  • 当一个线程完成的时候,主线程能够立即知道
  • 让多线程和多进程编码接口一致

使用线程池/进程池来管理并发编程,只要将相应的 task 函数提交给线程池/进程池,剩下的事情就由线程池/进程池来搞定。

ThreadPoolExecutor构造函数有两个参数:

一个是max_workers参数,用于指定线程池的最大线程数,如果不指定的话则默认是CPU核数的5倍。

另一个参数是thread_name_prefix,它用来指定线程池中线程的名称前缀(可选),如下:

threadPool = ThreadPoolExecutor(max_workers=self.max_workers, thread_name_prefix="test_")

Exectuor 提供了如下常用方法:

方法 描述
submit(fn, *args, **kwargs) 将 fn 函数提交给线程池。*args 代表传给 fn 函数的参数,**kwargs 代表以关键字参数的形式为 fn 函数传入参数
map(func,*iterables, timeout=None, chunksize=1) 该函数类似于全局函数 map(func, *iterables),只是该函数将会启动多个线程,以异步方式立即对 iterables 执行 map 处理
shutdown(wait=True) 关闭线程池。wait=True,等待池内所有任务执行完毕回收完资源后才继续;wait=False,立即返回,并不会等待池内的任务执行完毕。但不管wait参数为何值,整个程序都会等到所有任务执行完毕

程序将 task 函数提交(submit)给线程池后,submit 方法会返回一个 Future 对象,Future 类主要用于获取线程任务函数的返回值。由于线程任务会在新线程中以异步方式执行,因此线程执行的函数相当于一个“将来完成”的任务,所以 Python 使用 Future 来代表。

Future 提供了如下方法:

方法 描述
cancel() 取消该 Future 代表的线程任务。如果该任务正在执行,不可取消,则该方法返回 False;否则,程序会取消该任务,并返回 True
cancelled() 返回 Future 代表的线程任务是否被成功取消
running() 如果该 Future 代表的线程任务正在执行、不可被取消,该方法返回 True
done() 如果该 Funture 代表的线程任务被成功取消或执行完成,则该方法返回 True
result(timeout=None) 获取该 Future 代表的线程任务最后返回的结果。如果 Future 代表的线程任务还未完成,该方法将会阻塞当前线程,其中 timeout 参数指定最多阻塞多少秒
exception(timeout=None) 获取该 Future 代表的线程任务所引发的异常。如果该任务成功完成,没有异常,则该方法返回 None
add_done_callback(fn) 为该 Future 代表的线程任务注册一个“回调函数”,当该任务成功完成时,程序会自动触发该 fn 函数

线程池用完后,应调用线程池的shutdown()方法,关闭线程池。也可使用with语句来管理线程池,可避免手动关闭线程池

示例一(使用submit方式):

from concurrent.futures import ThreadPoolExecutor # 导入ThreadPoolExecutor模块
import time

max_workers = 5
t = []
t1 = time.time()

# 作为线程任务的函数
def task(x, y):
    return x + y

threadPool = ThreadPoolExecutor(max_workers)    # 创建最大线程数为max_workers的线程池

for i in range(20):     # 循环向线程池中提交task任务
    future = threadPool.submit(task, i, i+1)
    t.append(future)

# 若不需要获取返回值,则可不需要下面两行代码
for i in t:
    print(i.result())   # 获取每个任务的返回值,result()会阻塞主线程

threadPool.shutdown()   # 阻塞主线程,所有任务执行完后关闭线程池
print(time.time() - t1)

示例二(使用map方式):

from concurrent.futures import ThreadPoolExecutor	# 导入ThreadPoolExecutor模块

max_workers = 5
t = []
t1 = time.time()

# 作为线程任务的函数
def task(x):
    return x + (x + 1)

args = (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19)

with ThreadPoolExecutor(max_workers) as threadPool:   # 创建最大线程数为max_workers的线程池
    results = threadPool.map(task, args)    # 启动线程,并收集每个线任务的返回结果

    # 若无返回值,则可不需要下面两行代码
    for i in results:
        print(i)   

示例三:

as_complete():是一个生成器,在没有任务完成的时候会阻塞,在有某个任务完成的时候会yield这个任务,执行语句,继续阻塞,循环到所有任务结束,先完成的任务会先通知主线程

from concurrent.futures import ThreadPoolExecutor, as_completed
import time

max_workers = 5
t = []
t1 = time.time()

# 作为线程任务的函数
def task(x, y):
    return x + y

def handle_result(future):
    print(future.result())

with ThreadPoolExecutor(max_workers) as threadPool:    # 创建最大线程数为max_workers的线程池

    for i in range(20):     # 循环向线程池中提交task任务
        future = threadPool.submit(task, i, i+1)
        t.append(future)

    # 若不需要获取返回值,则可不需要下面两行代码
    for future in as_completed(t):  # as_completed,哪个先完成就先处理哪个,会阻塞主线程,直到完成所有,除非设置timeout
        future.add_done_callback(handle_result)

到此这篇关于浅谈一下python线程池简单应用的文章就介绍到这了,更多相关python线程池简单应用内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • python QT界面关闭线程池的线程跟随退出完美解决方案

    目录 方法一.线程池执行的循环代码为自己写的情况 方法二.线程池中执行的循环为调用的模块内的方法 方法一.线程池执行的循环代码为自己写的情况 定义一个全局变量,默认为T,当QT界面关闭后,将该变量值改为F. 线程执行的循环代码内增加一个判断方法,每次循环之前对全局变量进行判断,如果结果为T则进行循环.如果为F,则break退出循环,结束线程 from concurrent.futures import ThreadPoolExecutor import time a = True # 设置全局变

  • Python实现线程池工作模式的案例详解

    目录 01.客户机/服务器通信逻辑 02.数据交换协议 03.服务器主体逻辑 04.服务器会话线程 05.客户机主体逻辑 06.客户机发送数据 07.客户机接收数据 08.客户机界面设计 09.线程池 10.联合测试 11.小结 本文章基于苹果树病虫害预测模型,自定义应用层通信逻辑,设计服务器与客户机.客户机向服务器发送图像数据,服务器回送预测结果.为增强服务器的可靠性与可扩展性,服务器端采用线程池工作模式.为了增强客户机的可操作性,客户机采用PyQt5完成图形化界面设计. 01.客户机/服务器

  • python线程池ThreadPoolExecutor,传单个参数和多个参数方式

    目录 python线程池ThreadPoolExecutor,传单个参数和多个参数 这是线程池传单个参数的 下面是传多个参数的 python线程池传入多个参数 ThreadPoolExecutor.submit 多参数支持 总结 python线程池ThreadPoolExecutor,传单个参数和多个参数 这是线程池传单个参数的 from concurrent.futures import ThreadPoolExecutor,as_completed def test(a):        

  • 浅谈一下python线程池简单应用

    一.线程池简介 传统多线程方案会使用“即时创建,即时销毁”的策略.尽管与创建进程相比,创建线程的时间已经大大的缩短,但是如果提交给线程的任务时执行时间较短,而且执行次数及其频繁,那么服务器将处于不停的创建线程,销毁线程的状态. 一个线程的运行时间可以分为三部分:线程的启动时间.线程体的运行时间和线程的销毁时间. 在多线程处理的情景中,如果线程不能被重用,就意味着每次线程运行都要经过启动.销毁和运行3个过程.这必然会增加系统相应的时间,减低了效率. 线程池在系统启动时即创建大量空闲的线程,程序只要

  • 浅谈Java关闭线程池shutdown和shutdownNow的区别

    目录 前言 项目环境 1.线程池示例 2.shutdown 3.isShutdown 4.isTerminated 5.awaitTermination 6.shutdownNow 7.shutdown 和 shutdownNow 的区别? 前言 本章分为两个议题 如何正确关闭线程池 shutdown 和 shutdownNow 的区别 项目环境 jdk 1.8 github 地址:https://github.com/huajiexiewenfeng/java-concurrent 本章模块:

  • 浅谈Android中线程池的管理

    说到线程就要说说线程机制 Handler,Looper,MessageQueue 可以说是三座大山了 Handler Handler 其实就是一个处理者,或者说一个发送者,它会把消息发送给消息队列,也就是Looper,然后在一个无限循环队列中进行取出消息的操作 mMyHandler.sendMessage(mMessage); 这句话就是我耗时操作处理完了,我发送过去了! 然后在接受的地方处理!简单理解是不是很简单. 一般我们在项目中异步操作都是怎么做的呢? // 这里开启一个子线程进行耗时操作

  • Python 线程池用法简单示例

    本文实例讲述了Python 线程池用法.分享给大家供大家参考,具体如下: # -*- coding:utf-8 -*- #! python3 ''' Created on 2019-10-2 @author: Administrator ''' from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor import os,time,random def task(n): print('%s is runing' %

  • python线程池threadpool实现篇

    本文为大家分享了threadpool线程池中所有的操作,供大家参考,具体内容如下 首先介绍一下自己使用到的名词: 工作线程(worker):创建线程池时,按照指定的线程数量,创建工作线程,等待从任务队列中get任务: 任务(requests):即工作线程处理的任务,任务可能成千上万个,但是工作线程只有少数.任务通过          makeRequests来创建 任务队列(request_queue):存放任务的队列,使用了queue实现的.工作线程从任务队列中get任务进行处理: 任务处理函

  • 浅谈使用Python变量时要避免的3个错误

    Python编程中经常遇到一些莫名其妙的错误, 其实这不是语言本身的问题, 而是我们忽略了语言本身的一些特性导致的,今天就来看下使用Python变量时导致的3个不可思议的错误, 以后在编程中要多多注意. 关于Python编程运行时新手易犯错误,这里暂不作介绍,详情参见:Python运行的17个时新手常见错误小结 1. 可变数据类型作为函数定义中的默认参数 这似乎是对的?你写了一个小函数,比如,搜索当前页面上的链接,并可选将其附加到另一个提供的列表中. def search_for_links(p

  • 浅谈使用Python内置函数getattr实现分发模式

    本文研究的主要是使用Python内置函数getattr实现分发模式的相关问题,具体介绍如下. getattr 常见的使用模式是作为一个分发者.举个例子,如果你有一个程序可以以不同的格式输出数据,你可以为每种输出格式定义各自的格式输出函数,然后使用唯一的分发函数调用所需的格式输出函数. 例如,让我们假设有一个以 HTML.XML 和普通文本格式打印站点统计的程序.输出格式在命令行中指定,或者保存在配置文件中.statsout 模块定义了三个函数:output_html.output_xml 和 o

  • Python线程池模块ThreadPoolExecutor用法分析

    本文实例讲述了Python线程池模块ThreadPoolExecutor用法.分享给大家供大家参考,具体如下: python3内置的有Threadingpool和ThreadPoolExecutor模块,两个都可以做线程池,当然ThreadPoolExecutor会更好用一些,而且也有ProcessPoolExecutor进程池模块,使用方法基本一致. 首先导入模块 from concurrent.futures import ThreadPoolExecutor 使用方法很简单,最常用的可能就

  • python线程池如何使用

    线程池的使用 线程池的基类是 concurrent.futures 模块中的 Executor,Executor 提供了两个子类,即 ThreadPoolExecutor 和ProcessPoolExecutor,其中 ThreadPoolExecutor 用于创建线程池,而 ProcessPoolExecutor 用于创建进程池. 如果使用线程池/进程池来管理并发编程,那么只要将相应的 task 函数提交给线程池/进程池,剩下的事情就由线程池/进程池来搞定. Exectuor 提供了如下常用方

  • 浅谈对python中if、elif、else的误解

    今天下午在练习python时用了"if...if...else..."的分支结构,结果运行出来吓我一跳.原来我想当然的认为"if...if...else..."是"if...elif...else..."的简化结构(这个错误的看法好像还是从学C语言继承过来的).学了这么多天才发现其中的区别啊.下面先说说python,然后再说一下C语言里面的if语句. "python中通过if.elif.else等保留字提供单分支.二分支和多分支结构.&

随机推荐