9.4 KiB
9.4 KiB
天气数据自动采集与推送系统——多线程并发采集多城市数据 教学设计
| 课题 | 天气数据自动采集与推送系统——多线程并发采集多城市数据 |
|---|---|
| 课时 | 1课时(40分钟) |
| 教学目标 | 知识目标:理解进程与线程的概念及区别,掌握Python多线程编程的基本原理,了解并发编程在提升I/O密集型任务效率中的作用。 技能目标:能够使用threading模块创建和管理线程,能够改造单线程的天气数据采集代码为多线程并发版本,能够使用线程池(ThreadPoolExecutor)批量处理多城市数据采集任务,能够测量并对比串行与并发执行的性能差异。 素养目标:建立"并发优化"的工程思维,理解多线程在网络请求场景中的实用价值,培养通过技术手段提升程序性能的意识。 |
| 教学重难点 | 重点:threading模块的基本使用方法;线程的创建、启动与等待;ThreadPoolExecutor的应用;多线程访问共享数据的注意事项。 难点:理解多线程的并发执行机制与线程切换;处理多线程中的数据收集与结果汇总;避免线程安全问题(如数据竞争)。 |
| 教学资源准备 | 多媒体课件(含进程与线程对比图、并发执行动画);上节课完成的weather_fetcher.py模块;多城市代码列表文件;性能测试脚本模板;线程池使用示例代码。 |
教学过程
| 教学环节 | 教学内容 | 教师活动 | 学生活动 | 设计意图 |
|---|---|---|---|---|
| 1. 性能瓶颈引入 (6分钟) |
演示串行采集10个城市天气数据的耗时问题,提出"如何加速数据采集"的技术需求,引入多线程并发编程的概念。 | 问题演示 运行上节课的weather_fetcher模块,用循环串行采集10个城市,用time模块记录总耗时(约10-15秒),提问:"如果要采集100个城市呢?" 概念引入 展示并发执行示意图,说明"同时发送多个请求"的思想,介绍线程是实现并发的一种方式。 |
观察分析 观看串行执行过程,感受耗时问题,理解在网络请求中"等待响应"的时间占主导; 讨论思考 小组讨论:"能否让程序同时请求多个城市的数据?"初步建立并发需求认知。 |
通过实际运行建立性能痛点,让学生体会"串行等待"的低效;通过对比引出并发方案,明确本课时要解决的核心问题。 |
| 2. 多线程原理讲解 (8分钟) |
讲解进程与线程的基本概念、区别与应用场景,介绍Python的threading模块,演示线程的创建、启动与join()方法的使用。 | 概念对比 用类比说明:进程是独立的程序实例(如打开的软件),线程是程序内部的执行路径(如软件的多个功能同时运行);强调线程共享内存、切换快的特点; 基础演示 编写简单示例: python<br>import threading<br>def task(name):<br> print(f"{name}线程执行中")<br>t1 = threading.Thread(target=task, args=("A",))<br>t1.start()<br>t1.join()<br>讲解Thread对象创建、target参数、start()启动、join()等待。 |
聆听理解 理解"并发≠并行"的概念,记录线程的三要素:目标函数、参数、启动方法; 代码跟随 在IDE中输入演示代码,运行观察线程执行效果,尝试创建多个线程并观察输出顺序的随机性。 |
通过类比降低抽象概念的理解难度;通过简单示例建立"创建线程-启动-等待"的基本操作流程,为后续复杂应用打基础。 |
| 3. 并发采集实现 (12分钟) |
指导学生改造天气采集代码,使用线程实现多城市并发请求,演示ThreadPoolExecutor的使用方法,对比串行与并发的性能差异。 | 方案讲解 说明改造思路:为每个城市创建独立线程调用get_weather(),将结果存入列表; 代码演示 演示手动创建线程版本,然后引入线程池简化代码: python<br>from concurrent.futures import ThreadPoolExecutor<br>cities = ["北京", "上海", "广州", ...]<br>with ThreadPoolExecutor(max_workers=5) as executor:<br> results = executor.map(get_weather, cities)<br>讲解线程池的优势:自动管理线程数量、简化代码; 性能对比 分别运行串行版本和并发版本,展示耗时对比(如从15秒降至3秒)。 |
理解方案 理解"每个城市一个线程"的并发模型,记录线程池的使用模板; 实践编码 创建multi_thread_fetcher.py,使用ThreadPoolExecutor改造采集代码; 测试验证 运行代码,记录并对比串行与并发的耗时数据,体会性能提升。 |
通过代码改造巩固多线程应用能力;通过线程池简化实现,降低并发编程门槛;通过性能对比建立直观的"并发价值"认知。 |
| 4. 线程安全探讨 (10分钟) |
讲解多线程中的数据竞争问题,演示不安全的共享数据访问,介绍线程锁(Lock)的使用方法,指导学生在项目中安全收集结果。 | 问题演示 演示多线程同时修改同一列表可能出现的问题(如数据丢失),说明这是"数据竞争"; 解决方案 介绍threading.Lock()的使用: python<br>lock = threading.Lock()<br>with lock:<br> shared_list.append(data)<br>强调在项目中应使用线程安全的数据结构或加锁保护; 最佳实践 推荐使用线程池的map()或submit()方法返回结果,避免手动管理共享数据。 |
观察问题 观看演示,理解多线程同时访问数据的风险; 学习方案 理解Lock的"互斥访问"机制,记录加锁的代码模板; 优化代码 检查自己的并发采集代码,确保结果收集方式是线程安全的,如使用executor.map()的返回值而非手动append。 |
通过问题演示建立线程安全意识;通过解决方案教学培养规范编程习惯;通过代码优化强化"安全第一"的工程理念。 |
| 5. 项目集成与展望 (4分钟) |
总结多线程并发编程的核心要点,将本课时的并发采集模块集成到项目中,预告后续课程将实现定时自动采集与数据存储。 | 知识总结 回顾threading模块使用流程、ThreadPoolExecutor优势、线程安全注意事项; 模块集成 说明multi_thread_fetcher可作为项目的"高效采集引擎",后续定时任务将调用此模块; 任务布置 课后任务:尝试调整线程池的max_workers参数(如5、10、20),测试不同线程数对性能的影响,思考最优值。 |
回顾反思 总结并发编程的关键点,明确本模块在项目中的"性能优化"作用; 接收任务 记录课后任务,理解这是对并发性能调优的探索性实验。 |
通过总结强化知识结构;通过模块集成保持项目连贯性;课后任务引导学生探索并发参数优化,培养实验精神。 |
板书设计
多线程并发采集架构
串行模式(慢):
城市1 → 等待 → 城市2 → 等待 → 城市3 → ...
总耗时 = 单次耗时 × 城市数量
并发模式(快):
城市1 ↘
城市2 → 线程池 → 同时发送请求 → 并发等待
城市3 ↗
总耗时 ≈ 单次耗时
核心代码:
from concurrent.futures import ThreadPoolExecutor
with ThreadPoolExecutor(max_workers=5) as executor:
results = list(executor.map(get_weather, cities))
线程安全原则: 避免多线程同时修改共享数据
教学成效与反思
| 教学成效 | 结合本课时项目任务评估:90%学生成功使用ThreadPoolExecutor实现多城市并发采集,80%学生能够通过性能测试数据说明并发的优势。通过串行与并发的直观对比(耗时从15秒降至3秒),学生对多线程价值有了深刻认知,学习积极性高。线程池的引入有效降低了并发编程复杂度,学生普遍反馈"比想象中简单"。项目的并发采集模块已具备实用性,为后续定时任务提供了高效的数据获取能力。线程安全环节虽有难度,但通过问题演示和最佳实践指导,学生建立了基本的安全意识。 |
| 教学反思 | 本课时成功将"多线程与并发编程"这一传统难点,转化为"提升天气采集速度"的具体优化任务,学生的学习动机强且目标明确。性能对比实验设计合理,数据直观有说服力。线程池的引入时机恰当,避免了过早陷入底层线程管理的复杂性。不足之处:①在40分钟内,线程安全部分讲解略显紧凑,部分学生对Lock的理解停留在"照搬代码"层面,建议后续增加一个专门的线程安全小案例演示;②对"I/O密集型 vs CPU密集型"的区分提及较少,少数学生可能误以为多线程适用所有场景,建议增加一句说明"多线程适合网络请求等待多的任务";③课后任务的参数调优实验虽有探索性,但缺少对"过多线程可能导致性能下降"的提示,建议补充说明。整体上,项目驱动使并发编程学习变得具体可感,学生编写的并发模块已达到生产级代码的雏形,教学目标达成度高。 |