Python 多线程
Python 多线程简介
Python 是当今最受欢迎和多功能的编程语言之一,广泛应用于各个行业,包括 web 开发、机器学习和数据科学。鉴于其在相关领域(如机器学习和大数据)中的广泛应用和高需求,Python 已经超越 Java 成为顶级编程语言。
在本文中,我们将介绍 Python 多线程及其工作原理。我们将涵盖以下内容:
- 什么是多线程?
- 什么是进程
- 多线程的优势
- 守护线程(Daemon Thread)
- Python 多线程函数
threading.active_count()
threading.main_thread()
threading.Timer()
- 使用锁进行同步
什么是多线程?
多线程是指程序中可以独立于其他部分并发执行的一系列指令。
可以将它们视为进程中的不同单元,这些单元在被调度时可以独立完成任务。
当线程需要等待缓慢的外部操作(如网络请求或磁盘访问)完成时,它们会暂时休眠,从而使调度器可以将时间分配给其他线程执行。
什么是进程?
进程是计算机程序的一个可执行实例。
通常,一个进程是在单个控制流序列中执行的。
进程是操作系统分配资源的基本单位,每个进程包含一个或多个线程。
进程之间是隔离的,每个进程拥有自己的内存空间和系统资源。
多线程的优势
-
提高性能:
- 多核处理器:多线程程序在多核处理器系统上可以并行执行多个任务,从而显著提高性能。
- I/O 绑定任务:多线程特别适用于 I/O 绑定任务,如网络请求和磁盘访问。当一个线程等待 I/O 操作完成时,其他线程可以继续执行,充分利用 CPU 时间。
-
资源共享:
- 共享内存:同一个进程中的线程可以共享内存,包括全局变量。如果一个线程修改了全局变量的值,这些更改对所有线程都可见,简化了数据共享和通信。
基本的 Python 多线程程序
以下代码是基本的 Python 多线程程序,我们导入了 threading
模块,并创建了一个名为 t
的线程。这个线程 t
将运行 show
函数。
import threading
def show():
print(f"Thread {threading.current_thread().name} is running")
# 创建一个线程
t = threading.Thread(target=show, name="MyThread")
# 启动线程
t.start()
# 等待线程完成
t.join()
print("Main thread has completed")
守护线程 (Daemon Thread)
守护线程是一种在后台运行的线程,它不会阻止主程序的退出。当主程序的所有非守护线程(即用户线程)结束时,守护线程也会自动终止。守护线程通常用于执行一些辅助性任务,如定期保存数据、监控系统状态等。
示例
下面是一个简单的 Python 示例,展示了如何创建和使用守护线程:
import threading
import time
def background_task():
count = 0
while True:
print(f"Background task {count}")
count += 1
time.sleep(1)
# 创建一个守护线程
t = threading.Thread(target=background_task, daemon=True)
t.name = "BackgroundThread"
# 启动线程
t.start()
# 主程序继续执行
print("Main thread is running...")
# 让主程序运行一段时间
time.sleep(5)
print("Main thread has completed")
关键点
- 守护线程:通过设置
daemon=True
,线程成为守护线程。当主程序的所有非守护线程结束时,守护线程会自动终止。 - 无限循环:守护线程通常用于执行无限循环的任务,这些任务不需要在主程序结束时显式地停止。
- 线程名称:可以通过
t.name
设置线程的名称,方便调试和日志记录。
Python 线程相关函数
Python 的 threading
模块提供了多种功能来管理和控制线程。以下是一些常用的线程相关函数及其示例:
1. threading.active_count()
这个函数返回当前正在执行的线程数量。
示例:
import threading
def show():
print(f"Thread {threading.current_thread().name} is running")
# 创建并启动两个线程
t1 = threading.Thread(target=show, name="Thread1")
t2 = threading.Thread(target=show, name="Thread2")
t1.start()
t2.start()
# 输出当前活跃线程的数量
print(f"Number of active threads: {threading.active_count()}")
# 等待所有线程完成
t1.join()
t2.join()
输出:
Thread Thread1 is running
Thread Thread2 is running
Number of active threads: 3
Main thread has completed
2. threading.main_thread()
这个函数返回程序的主线程对象。
示例:
import threading
def show():
print(f"Thread {threading.current_thread().name} is running")
# 创建并启动一个线程
t = threading.Thread(target=show, name="MyThread")
t.start()
# 获取主线程
main_thread = threading.main_thread()
print(f"Main thread name: {main_thread.name}")
# 等待线程完成
t.join()
输出:
Thread MyThread is running
Main thread name: MainThread
3. threading.Timer()
这个函数用于创建一个新的线程,并指定该线程在一定时间后启动。一旦启动,它会调用指定的函数。
示例:
import threading
import time
def delayed_task():
print("Delayed task executed")
# 创建一个定时器线程,3秒后执行 delayed_task 函数
timer = threading.Timer(3, delayed_task)
timer.start()
# 主程序继续执行
print("Main thread is running...")
# 让主程序运行一段时间
time.sleep(5)
print("Main thread has completed")
输出:
Main thread is running...
Delayed task executed
Main thread has completed
代码解释
-
threading.active_count()
:- 该函数返回当前正在执行的线程数量。
- 在示例中,我们创建并启动了两个线程,然后输出当前活跃线程的数量。
-
threading.main_thread()
:- 该函数返回程序的主线程对象。
- 在示例中,我们获取了主线程的名称并输出。
-
threading.Timer()
:- 该函数用于创建一个定时器线程,指定延迟时间和要执行的函数。
- 在示例中,我们创建了一个定时器线程,3秒后执行
delayed_task
函数。
使用锁进行同步
在多线程编程中,锁(Lock)是一种重要的同步机制,用于确保多个线程不会同时访问共享资源,从而避免竞态条件(race conditions)。Python 的 threading
模块提供了 Lock
类来实现这一功能。Lock
类有两个主要方法:acquire()
和 release()
。
方法说明
-
acquire()
:- 用于获取锁。如果锁已经被其他线程持有,则调用
acquire()
的线程会被阻塞,直到锁被释放。 - 可以选择性地传递一个超时参数
timeout
,以防止线程无限期地等待锁。
- 用于获取锁。如果锁已经被其他线程持有,则调用
-
release()
:- 用于释放锁。如果锁未被当前线程持有,则会引发
RuntimeError
异常。
- 用于释放锁。如果锁未被当前线程持有,则会引发
示例
下面是一个使用锁来同步两个线程的简单示例:
import threading
# 共享资源
shared_resource = 0
# 创建一个锁对象
lock = threading.Lock()
def increment():
global shared_resource
for _ in range(1000000):
lock.acquire()
shared_resource += 1
lock.release()
def decrement():
global shared_resource
for _ in range(1000000):
lock.acquire()
shared_resource -= 1
lock.release()
# 创建两个线程
t1 = threading.Thread(target=increment)
t2 = threading.Thread(target=decrement)
# 启动线程
t1.start()
t2.start()
# 等待线程完成
t1.join()
t2.join()
# 输出最终的共享资源值
print(f"Final value of shared resource: {shared_resource}")
代码解释
-
导入
threading
模块:import threading
-
定义共享资源:
shared_resource = 0
-
创建锁对象:
lock = threading.Lock()
-
定义
increment
函数:def increment(): global shared_resource for _ in range(1000000): lock.acquire() shared_resource += 1 lock.release()
- 这个函数会增加
shared_resource
的值 1000000 次。每次操作前先获取锁,操作完成后释放锁。
- 这个函数会增加
-
定义
decrement
函数:def decrement(): global shared_resource for _ in range(1000000): lock.acquire() shared_resource -= 1 lock.release()
- 这个函数会减少
shared_resource
的值 1000000 次。每次操作前先获取锁,操作完成后释放锁。
- 这个函数会减少
-
创建并启动线程:
t1 = threading.Thread(target=increment) t2 = threading.Thread(target=decrement) t1.start() t2.start()
-
等待线程完成:
t1.join() t2.join()
-
输出最终的共享资源值:
print(f"Final value of shared resource: {shared_resource}")
预期输出
由于 increment
和 decrement
每个都执行 1000000 次,并且使用锁来同步,最终的 shared_resource
应该是 0。
注意事项
- 死锁:如果一个线程获取了多个锁,但没有按正确的顺序释放,可能会导致死锁。使用锁时要小心,确保每个锁都能正确地被释放。
- 性能:频繁地获取和释放锁可能会影响性能,因此在实际应用中需要权衡同步的需求和性能的影响。
总结
在这篇文章中,我们探讨了 Python 多线程的基本概念。我们学习了与多线程相关的不同函数和对象,包括:
-
threading.active_count()
:- 用于获取当前正在执行的线程数量。
-
threading.main_thread()
:- 用于获取程序的主线程对象。
-
threading.Timer()
:- 用于创建一个定时器线程,指定延迟时间后执行特定的函数。
-
锁(Lock):
- 用于同步多个线程,避免竞态条件。锁的主要方法有
acquire()
和release()
。
- 用于同步多个线程,避免竞态条件。锁的主要方法有
通过这些基本概念和示例,你可以更好地理解和使用 Python 的多线程功能来开发高效的并发应用程序。
原文地址:https://blog.csdn.net/woshichenpi/article/details/143524358
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!