Files
teaching-design/data/Python/9.md
2026-06-15 00:55:47 -06:00

9.4 KiB
Raw Blame History

天气数据自动采集与推送系统——多线程并发采集多城市数据 教学设计

课题 天气数据自动采集与推送系统——多线程并发采集多城市数据
课时 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密集型"的区分提及较少,少数学生可能误以为多线程适用所有场景,建议增加一句说明"多线程适合网络请求等待多的任务";③课后任务的参数调优实验虽有探索性,但缺少对"过多线程可能导致性能下降"的提示,建议补充说明。整体上,项目驱动使并发编程学习变得具体可感,学生编写的并发模块已达到生产级代码的雏形,教学目标达成度高。