百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术资源 > 正文

Python多线程:让程序 “多线作战” 的秘密武器

off999 2025-06-24 15:57 30 浏览 0 评论


一、什么是多线程?

在日常生活中,我们可以一边听音乐一边浏览新闻,这就是 “多任务处理”。在Python编程里,多线程同样允许程序同时执行多个任务,从而提升程序的执行效率和响应速度 。不过,Python中的多线程由于全局解释器锁(GIL)的存在,在CPU密集型任务中表现受限,但在I/O密集型任务(如网络请求、文件读写)中却能大放异彩。

二、Python多线程核心函数及案例

1. threading.Thread()

功能:用于创建线程对象,是多线程编程的基础。通过传入target参数指定线程要执行的函数,args参数传递函数所需的参数。

案例:同时打印两条不同的消息,模拟多任务执行。

import threading
import time

def print_message(message):
    for _ in range(3):
        print(message)
        time.sleep(1)

thread1 = threading.Thread(target=print_message, args=("线程1正在工作",))
thread2 = threading.Thread(target=print_message, args=("线程2正在工作",))

thread1.start()
thread2.start()

thread1.join()
thread2.join()
print('主程序执行结束')


#程序执行后打印如下:
线程1正在工作
线程2正在工作
线程1正在工作
线程2正在工作
线程1正在工作
线程2正在工作
主程序执行结束

#多次执行后可能如下:
线程1正在工作
线程2正在工作
线程1正在工作线程2正在工作

线程1正在工作
线程2正在工作
主程序执行结束

解析:定义print_message函数用于打印消息,创建thread1和thread2两个线程对象,分别传入不同的消息作为参数。调用start()方法启动子线程,线程开始并行执行对应的函数;join()方法会阻塞主线程(主程序执行时就算一个主线程),等待子线程执行完毕。

以上结果因为添加了join函数,主程序最后的print打印消息是在最后才执行,但是子线程打印消息还是出现了跟预期不一致的地方。如果注释掉上面的join方法,多次执行结果可能如下:会发现主程序的print日志混在了子线程print日志中间,原因是因为主线程和子线程同时操作print函数导致的。

#结果1
线程1正在工作
线程2正在工作
主程序执行结束
线程1正在工作线程2正在工作

线程2正在工作
线程1正在工作

#结果2
线程1正在工作
线程2正在工作
主程序执行结束
线程1正在工作
线程2正在工作
线程1正在工作线程2正在工作

2. threading.Lock()

功能:创建锁对象,用于解决多线程中共享资源的竞争问题,避免数据不一致。当一个线程获取锁后,其他线程必须等待,直到该线程释放锁。

案例:接着上面的案例,我们通过对print打印加锁,保证同一时间只有一个线程操作print打印。

通过threading.Lock()定义锁对象,通过lock.acquire()加锁,lock.release()释放锁。


import threading
import time

lock = threading.Lock()
def print_message(message):
    for _ in range(3):
        lock.acquire()
        print(message)
        lock.release()
        time.sleep(1)

thread1 = threading.Thread(target=print_message, args=("线程1正在工作",))
thread2 = threading.Thread(target=print_message, args=("线程2正在工作",))

thread1.start()
thread2.start()

thread1.join()
thread2.join()
print('主程序执行结束')

#程序执行后,结果如下:不会出现打印错乱的情况
线程1正在工作
线程2正在工作
线程1正在工作
线程2正在工作
线程1正在工作
线程2正在工作
主程序执行结束

3. threading.Timer()

功能:创建一个定时器线程,在指定的延迟时间后执行函数。

案例:延迟3秒后打印提示信息。

import threading

def delayed_function(name):
    print(f"3秒已到,{name}开始执行任务!")
#定时三秒
timer = threading.Timer(3, delayed_function,args=('线程1',))

timer.start()

解析:threading.Timer(3, delayed_function)表示创建一个延迟 3 秒后执行delayed_function的定时器线程,调用start()启动定时器。

4. threading.current_thread()

功能:返回当前正在执行的线程对象。

案例:在函数中查看当前执行的线程。

import threading
def check_thread():
    current = threading.current_thread()
    print(f"当前执行的线程是: {current.name}")
#子线程执行
thread = threading.Thread(target=check_thread)
thread.start()
#主程序执行
check_thread()

#结果:
当前执行的线程是: Thread-1 (check_thread)
当前执行的线程是: MainThread

解析:check_thread函数中使用threading.current_thread()获取当前线程对象,并打印线程名称,既在子线程中调用,也在主线程中调用,对比输出结果。

5. threading.active_count()

功能:返回当前活动的线程数量(包括主线程)。

案例:统计程序中活动线程数。

import threading
import time


def thread_task():
    time.sleep(2)

threads = []
for _ in range(3):
    t = threading.Thread(target=thread_task)
    threads.append(t)
    t.start()

print(f"启动子线程后,活动线程数: {threading.active_count()}")

for t in threads:
    t.join()

print(f"子线程执行完毕后,活动线程数: {threading.active_count()}")

#执行结果
启动子线程后,活动线程数: 4
子线程执行完毕后,活动线程数: 1

解析:创建3个子线程并启动,使用threading.active_count()分别在启动子线程后和子线程执行完毕后统计活动线程数量,子线程结束后主线程还在,所以最后还统计到1个。

6.threading.local()

功能:threading.local用于创建线程局部变量,每个线程都有自己独立的变量副本,线程之间的变量互不干扰。

案例:模拟多线程处理用户请求,每个线程记录自己处理的请求编号。

import threading

# 创建threading.local对象
local_data = threading.local()


def process_request(request_id):
    # 为每个线程设置独立的请求编号
    local_data.request_id = request_id
    print(f"线程 {threading.current_thread().name} 正在处理请求 {local_data.request_id}")
    # 在同一线程的其他函数中使用该变量
    additional_processing()


def additional_processing():
    print(f"线程 {threading.current_thread().name} 继续处理请求 {local_data.request_id}")


threads = []
for i in range(3):
    t = threading.Thread(target=process_request, args=(i,))
    threads.append(t)
    t.start()

for t in threads:
    t.join()

#结果:
线程 Thread-1 (process_request) 正在处理请求 0
线程 Thread-1 (process_request) 继续处理请求 0
线程 Thread-2 (process_request) 正在处理请求 1
线程 Thread-2 (process_request) 继续处理请求 1
线程 Thread-3 (process_request) 正在处理请求 2
线程 Thread-3 (process_request) 继续处理请求 2

解析:首先创threading.locallocal_data。process_request函数中,为每个线程设置独立request_id属性,不同线程local_data.request_id相互独立。additional_processing函数可以在同一线程内访问该属性,体现了线程局部变量在同一线程内共享、不同线程间隔离的特性。

三、实用案例详解

1. 多线程处理网络请求

场景:需要从多个网站获取数据,如果顺序执行,会浪费大量等待响应的时间。使用多线程可以同时发起多个请求,提高效率。

import requests
import threading


def fetch_data(url):
    try:
        response = requests.get(url)
        print(f"从 {url} 获取数据成功,状态码: {response.status_code}")
    except requests.RequestException as e:
        print(f"从 {url} 获取数据失败: {e}")


urls = [
    "https://www.example1.com",
    "https://www.example2.com",
    "https://www.example3.com"
]

threads = []
for url in urls:
    t = threading.Thread(target=fetch_data, args=(url,))
    threads.append(t)
    t.start()

for t in threads:
    t.join()

解析:定义fetch_data函数用于发送网络请求并处理响应,将多个 URL 放入列表,为每个 URL 创建一个线程发起请求,实现多任务并行处理网络请求。

2. 多线程实现文件读写

场景:同时读取多个文件并进行处理,或者同时向多个文件写入数据。

import threading

def read_file(file_path):
    try:
        with open(file_path, 'r') as file:
            content = file.read()
            print(f"读取 {file_path} 内容: {content}")
    except FileNotFoundError:
        print(f"{file_path} 不存在")


file_paths = ["file1.txt", "file2.txt", "file3.txt"]
threads = []
for path in file_paths:
    t = threading.Thread(target=read_file, args=(path,))
    threads.append(t)
    t.start()

for t in threads:
    t.join()

解析:read_file函数负责读取文件内容,通过多线程为每个文件路径创建线程,同时读取多个文件,提升文件处理效率。

4、总结

Python多线程是提升程序效率的有力工具,尤其在I/O密集型任务中优势显著。通过掌握threading模块的核心函数,灵活运用多线程技术,让程序实现 “多线作战”。但也要牢记多线程的局限性,不是线程越多越好,同时避免死锁,线程安全问题,最后选择合适的并发方案,才能发挥出 Python的最大潜力!

相关推荐

电脑里一堆microsoft visual

按照系统向下兼容原理,保留2010就可以了.1)你安装的时候是不是把创建快捷键的选项框都没选上,导致在开始菜单中没有找到相应的链接?2)去你的安装目录下,找到Microsoftvisualc++...

windows无法识别usb(windows无法识别usb设备)
windows无法识别usb(windows无法识别usb设备)

Windows无法识别USB,解决办法如下右键开始菜单打开设备管理器,在通用串行总线控制器中右键点击设备选择“卸载”,完成后重新启动计算机即可解决问题。这有可能是在组策略中禁用了USB口,可以使用快捷键【Win+R】运行gpedit.msc...

2025-11-10 11:51 off999

bios能看到硬盘 开机找不到硬盘

bios里可以看到硬盘,说明硬盘已经被主板识别。进系统找不到,可能硬盘没分区,或者硬盘是动态磁盘,还没有导入或激活。按win+r,输入diskmgmt.msc回车,就打开磁盘管理了,在里面可以给新硬盘...

找回qq聊天记录的方法(找回qq聊天记录怎么找)
  • 找回qq聊天记录的方法(找回qq聊天记录怎么找)
  • 找回qq聊天记录的方法(找回qq聊天记录怎么找)
  • 找回qq聊天记录的方法(找回qq聊天记录怎么找)
  • 找回qq聊天记录的方法(找回qq聊天记录怎么找)
无线网有个红叉(无线网有个红叉,搜索不到网络)

连接失败,路由坏换路由,外网坏,报修无线网络处出现红叉表示设备无法正常工作。请检查网卡驱动是否正常,无线网络开关是否打开。解决方法:查看电脑是否有无线网络开关,且是否打开。进入设备管理器检查网卡驱动是...

thinkpad笔记本官网首页(thinkpad官方商城)

官方网站 国内:http://www.thinkworld.com.cn   国内用户只需要访问国内即可。  ThinkPad,中文名为“思考本”,在2005年以前是IBMPC事业部旗下的便携式计算机...

win7什么版本最好用(win7哪个版本最稳定流畅)

Windows7旗舰版,最好,最稳定。Windows7,是由微软公司(Microsoft)开发的操作系统,内核版本号为WindowsNT6.1。Windows7可供选择的版本有:简易版(Sta...

win7自带虚拟光驱怎么使用(win7系统虚拟光驱安装教程)

以DAEMONTools为例,360软件管家里面就有最新版的下.安装后使用方法如下:第一种方法:在虚拟光驱界面中,你先按一下中间工具栏最左边“+”符号的按钮,添加镜像文件(可以一次添加多个),这...

电脑装系统蓝屏(电脑装系统蓝屏重启开不了机)

蓝屏的原因往往集中在不兼容的硬件和驱动程序、有问题的软件、病毒等。解决办法:1、病毒的原因。使用电脑管家杀毒。2、内存的原因。用橡皮擦把内存条的金手指擦拭一下,把氧化层擦掉,确保内存条安装、运行正常。...

u盘安装软件(u盘安装软件到电视)

第一种情况:软件安装包可以直接下载的。在电脑上将软件安装包下载到本地硬盘,然后将下载好软件安装包拷贝到U盘上即可拿到别的电脑上去安装。分可为exe格式的和rar格式,exe格式直接安装,rar格式的解...

microsoft官网账户注册(microsoft 帐户注册)

要创建Microsoft账户,您可以按照以下步骤进行操作:1.打开任意一个支持浏览器的设备,如电脑、手机或平板电脑。2.在浏览器中输入"Microsoft账户注册"或直接访问Mic...

outlookcom官网(outlook online archive auto)
  • outlookcom官网(outlook online archive auto)
  • outlookcom官网(outlook online archive auto)
  • outlookcom官网(outlook online archive auto)
  • outlookcom官网(outlook online archive auto)
显示器闪屏是什么原因(显示器闪屏是哪里坏了)

解决方法:  一、接触不良导致的显示器闪屏  先查看主机和显示器的电源线连接,是否松动,重新插拔一下电源线。  二、信号干扰导致的显示器闪屏  1、连接显示器的电缆线是否没有屏蔽线圈,如果没有防干扰的...

国产linux操作系统(国产linux操作系统有什么版本)

中国对于操作系统的探索其实并不晚。  早在20世纪60年代中期中国就开始操作系统的研发,那时的比尔·盖茨还只是个迷恋计算机的小字辈,南京大学教授孙钟秀、北京大学杨芙清院士等都是我国操作系统的拓荒者...

免费无需排队的云电脑(不需要排队的云电脑)

目前市场上有一些云游戏平台提供无限时长且无需排队的服务。这些平台通常采用先进的云计算技术和高性能服务器,能够提供稳定流畅的游戏体验。用户可以随时登录并畅玩游戏,无需等待排队。这些平台还提供多种游戏选择...

取消回复欢迎 发表评论: