Python 内置库 多线程threading使用讲解

简介: 本文介绍Python中的线程基础。首先展示了单线程的基本使用,然后通过`threading`模块创建并运行多线程。示例中创建了两个线程执行不同任务,并使用`active_count()`和`enumerate()`检查线程状态。接着讨论了守护线程,主线程默认等待所有子线程完成,但可设置子线程为守护线程使其随主线程一同结束。`join()`方法用于主线程阻塞等待子线程执行完毕,而线程池能有效管理线程,减少频繁创建的开销,Python提供`ThreadPoolExecutor`进行线程池操作。最后提到了GIL(全局解释器锁),它是CPython的机制,限制了多线程并行执行的能力,可能导致性能下降。

线程基本使用

单线程

def main():
    print("在扔一个苹果")

if __name__ == "__main__":
    main()

多线程

Python提供了thread、threading等模块来进行线程的创建与管理,后者在线程管理能力上更进一步,因此我们通常使用threading模块。创建一个线程需要指定该线程执行的任务(函数名)、以及该函数需要的参数,

import threading
import time
def apple_1():
    print("苹果1")
    time.sleep(1)
def apple_2():
    print("苹果2")
    time.sleep(1)
def main():
    thread = threading.Thread(target=apple_1)
    thread2 = threading.Thread(target=apple_2)
    thread.start()
    thread2.start()
    print("苹果3")
    print("有多少小小丑? ", threading.active_count())
    print("这些小丑是谁呢?", threading.enumerate())

if __name__ == "__main__":
    main()

守护线程

线程是程序执行的最小单位,Python在进程启动起来后,会自动创建一个主线程,之后使用多线程机制可以在此基础上进行分支,产生新的子线程。子线程启动起来后,主线程默认会等待所有线程执行完成之后再退出。但是我们可以将子线程设置为守护线程,此时主线程任务一旦完成,所有子线程将会和主线程一起结束(就算子线程没有执行完也会退出)。
守护线程可以在线程启动之前,通过setDaemon(True)的形式进行设置,或者在创建子线程对象时,以参数的形式指定:

thread01 = Thread(target=target01, args=“”, name=“线程1”, daemon=True)

但是需要注意,如果希望主程序不等待任何线程直接退出,只有所有的线程都被设置为守护线程才有用。

设置线程阻塞

我们可以用join()方法使主线程陷入阻塞,以等待某个线程执行完毕。因此这也是实现线程同步的一种方式。参数timeout 可以用来设置主线程陷入阻塞的时间,如果线程不是守护线程,即没有设置daemon为True,那么参数timeout 是无效的,主线程会一直阻塞,直到子线程执行结束。

线程池的使用

在程序运行过程之中,临时创建一个线程需要耗费不小的代价(包括与操作系统的交互部分),尤其是我们只对一个线程分配一个简短的任务,此时,频繁的线程创建将会严重拖垮程序的执行的效率。
因此,在这种情形下,我们可以选择采用线程池技术,即通过预先创建几个空闲线程,在需要多线程来处理任务时,将任务分配给一个处于空闲状态的线程,该线程在执行完成后,将会回归空闲状态,而不是直接销毁;而如果申请从线程池中分配一个空闲线程时,遇到所有线程均处于运行状态,则当前线程可以选择阻塞来等待线程资源的空闲。如此一来,程序对于线程的管理将会更加灵活。
Python从3.2开始,就将线程池作为内置模块包含了进来,可以通过concurrent.futures.ThreadPoolExecutor来调用,使用方法也很简单。

GIL 全局解释器锁

GIL(GlobalInterpreterLock,全局解释器锁)是CPython中采用的一种机制,它确保同一时刻只有一个线程在执行Python字节码。给整个解释器加锁使得解释器多线程运行更方便,而且开发的CPython也更易于维护,但是代价是牺牲了在多处理器上的并行性。因此,在相当多的场景中,CPython解释器下的多线程机制的性能都不尽如人意

import threading
import time

def task():
    a = 0
    while a < 9999*9999:
        a += 1


def main():
    start_time = time.time()
    thread = threading.Thread(target=task)
    thread2 = threading.Thread(target=task)
    thread2.start()
    thread.start()
    thread.join()
    thread2.join()
    task()
    print("all time: ", time.time() - start_time)
相关文章
|
18天前
|
数据采集 Java API
Jsoup库能处理多线程下载吗?
Jsoup库能处理多线程下载吗?
|
10天前
|
XML JSON 数据库
Python的标准库
Python的标准库
125 77
|
25天前
|
机器学习/深度学习 算法 数据挖掘
数据分析的 10 个最佳 Python 库
数据分析的 10 个最佳 Python 库
73 4
数据分析的 10 个最佳 Python 库
|
11天前
|
XML JSON 数据库
Python的标准库
Python的标准库
39 11
|
24天前
|
人工智能 API 开发工具
aisuite:吴恩达发布开源Python库,一个接口调用多个大模型
吴恩达发布的开源Python库aisuite,提供了一个统一的接口来调用多个大型语言模型(LLM)服务。支持包括OpenAI、Anthropic、Azure等在内的11个模型平台,简化了多模型管理和测试的工作,促进了人工智能技术的应用和发展。
97 1
aisuite:吴恩达发布开源Python库,一个接口调用多个大模型
|
11天前
|
数据可视化 Python
以下是一些常用的图表类型及其Python代码示例,使用Matplotlib和Seaborn库。
通过这些思维导图和分析说明表,您可以更直观地理解和选择适合的数据可视化图表类型,帮助更有效地展示和分析数据。
54 8
|
19天前
|
安全 API 文件存储
Yagmail邮件发送库:如何用Python实现自动化邮件营销?
本文详细介绍了如何使用Yagmail库实现自动化邮件营销。Yagmail是一个简洁强大的Python库,能简化邮件发送流程,支持文本、HTML邮件及附件发送,适用于数字营销场景。文章涵盖了Yagmail的基本使用、高级功能、案例分析及最佳实践,帮助读者轻松上手。
29 4
|
25天前
|
数据采集 存储 数据处理
Python中的多线程编程及其在数据处理中的应用
本文深入探讨了Python中多线程编程的概念、原理和实现方法,并详细介绍了其在数据处理领域的应用。通过对比单线程与多线程的性能差异,展示了多线程编程在提升程序运行效率方面的显著优势。文章还提供了实际案例,帮助读者更好地理解和掌握多线程编程技术。
|
网络协议 Python
python中的内置库socket
网络编程基础: * Sockets(套接字)可以在一个进程内,在同一机器上的进程之间,或者在不同主机的进程之间进行通信,主机可以是任何一台有连接互联网的机器。 * Socket主要是使用IP地址,协议,端口号来标识一个进程。端口号的范围为0~65535(用户端口号一般大于1024),协议有很多种,经常用到的就是TCP,IP,UDP等;
1233 0
|
17天前
|
人工智能 数据可视化 数据挖掘
探索Python编程:从基础到高级
在这篇文章中,我们将一起深入探索Python编程的世界。无论你是初学者还是有经验的程序员,都可以从中获得新的知识和技能。我们将从Python的基础语法开始,然后逐步过渡到更复杂的主题,如面向对象编程、异常处理和模块使用。最后,我们将通过一些实际的代码示例,来展示如何应用这些知识解决实际问题。让我们一起开启Python编程的旅程吧!