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

| **课题** | **天气数据自动采集与推送系统——多线程并发采集多城市数据** |
|---------|------------------------------------------|
| **课时** | 1课时(40分钟) |
| **教学目标** | **知识目标**：理解进程与线程的概念及区别，掌握Python多线程编程的基本原理，了解并发编程在提升I/O密集型任务效率中的作用。<br>**技能目标**：能够使用threading模块创建和管理线程，能够改造单线程的天气数据采集代码为多线程并发版本，能够使用线程池(ThreadPoolExecutor)批量处理多城市数据采集任务，能够测量并对比串行与并发执行的性能差异。<br>**素养目标**：建立"并发优化"的工程思维，理解多线程在网络请求场景中的实用价值，培养通过技术手段提升程序性能的意识。 |
| **教学重难点** | **重点**：threading模块的基本使用方法；线程的创建、启动与等待；ThreadPoolExecutor的应用；多线程访问共享数据的注意事项。<br>**难点**：理解多线程的并发执行机制与线程切换；处理多线程中的数据收集与结果汇总；避免线程安全问题（如数据竞争）。 |
| **教学资源准备** | 多媒体课件（含进程与线程对比图、并发执行动画）；上节课完成的weather_fetcher.py模块；多城市代码列表文件；性能测试脚本模板；线程池使用示例代码。 |

## 教学过程

| 教学环节 | 教学内容 | 教师活动 | 学生活动 | 设计意图 |
|:---------|:---------|:---------|:---------|:---------|
| **1. 性能瓶颈引入**<br>(6分钟) | 演示串行采集10个城市天气数据的耗时问题，提出"如何加速数据采集"的技术需求，引入多线程并发编程的概念。 | **问题演示**<br>运行上节课的weather_fetcher模块，用循环串行采集10个城市，用time模块记录总耗时（约10-15秒），提问："如果要采集100个城市呢？"<br><br>**概念引入**<br>展示并发执行示意图，说明"同时发送多个请求"的思想，介绍线程是实现并发的一种方式。 | **观察分析**<br>观看串行执行过程，感受耗时问题，理解在网络请求中"等待响应"的时间占主导；<br><br>**讨论思考**<br>小组讨论："能否让程序同时请求多个城市的数据？"初步建立并发需求认知。 | 通过实际运行建立性能痛点，让学生体会"串行等待"的低效；通过对比引出并发方案，明确本课时要解决的核心问题。 |
| **2. 多线程原理讲解**<br>(8分钟) | 讲解进程与线程的基本概念、区别与应用场景，介绍Python的threading模块，演示线程的创建、启动与join()方法的使用。 | **概念对比**<br>用类比说明：进程是独立的程序实例（如打开的软件），线程是程序内部的执行路径（如软件的多个功能同时运行）；强调线程共享内存、切换快的特点；<br><br>**基础演示**<br>编写简单示例：<br>```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>```<br>讲解Thread对象创建、target参数、start()启动、join()等待。 | **聆听理解**<br>理解"并发≠并行"的概念，记录线程的三要素：目标函数、参数、启动方法；<br><br>**代码跟随**<br>在IDE中输入演示代码，运行观察线程执行效果，尝试创建多个线程并观察输出顺序的随机性。 | 通过类比降低抽象概念的理解难度；通过简单示例建立"创建线程-启动-等待"的基本操作流程，为后续复杂应用打基础。 |
| **3. 并发采集实现**<br>(12分钟) | 指导学生改造天气采集代码，使用线程实现多城市并发请求，演示ThreadPoolExecutor的使用方法，对比串行与并发的性能差异。 | **方案讲解**<br>说明改造思路：为每个城市创建独立线程调用get_weather()，将结果存入列表；<br><br>**代码演示**<br>演示手动创建线程版本，然后引入线程池简化代码：<br>```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>```<br>讲解线程池的优势：自动管理线程数量、简化代码；<br><br>**性能对比**<br>分别运行串行版本和并发版本，展示耗时对比（如从15秒降至3秒）。 | **理解方案**<br>理解"每个城市一个线程"的并发模型，记录线程池的使用模板；<br><br>**实践编码**<br>创建multi_thread_fetcher.py，使用ThreadPoolExecutor改造采集代码；<br><br>**测试验证**<br>运行代码，记录并对比串行与并发的耗时数据，体会性能提升。 | 通过代码改造巩固多线程应用能力；通过线程池简化实现，降低并发编程门槛；通过性能对比建立直观的"并发价值"认知。 |
| **4. 线程安全探讨**<br>(10分钟) | 讲解多线程中的数据竞争问题，演示不安全的共享数据访问，介绍线程锁(Lock)的使用方法，指导学生在项目中安全收集结果。 | **问题演示**<br>演示多线程同时修改同一列表可能出现的问题（如数据丢失），说明这是"数据竞争"；<br><br>**解决方案**<br>介绍threading.Lock()的使用：<br>```python<br>lock = threading.Lock()<br>with lock:<br>    shared_list.append(data)<br>```<br>强调在项目中应使用线程安全的数据结构或加锁保护；<br><br>**最佳实践**<br>推荐使用线程池的map()或submit()方法返回结果，避免手动管理共享数据。 | **观察问题**<br>观看演示，理解多线程同时访问数据的风险；<br><br>**学习方案**<br>理解Lock的"互斥访问"机制，记录加锁的代码模板；<br><br>**优化代码**<br>检查自己的并发采集代码，确保结果收集方式是线程安全的，如使用executor.map()的返回值而非手动append。 | 通过问题演示建立线程安全意识；通过解决方案教学培养规范编程习惯；通过代码优化强化"安全第一"的工程理念。 |
| **5. 项目集成与展望**<br>(4分钟) | 总结多线程并发编程的核心要点，将本课时的并发采集模块集成到项目中，预告后续课程将实现定时自动采集与数据存储。 | **知识总结**<br>回顾threading模块使用流程、ThreadPoolExecutor优势、线程安全注意事项；<br><br>**模块集成**<br>说明multi_thread_fetcher可作为项目的"高效采集引擎"，后续定时任务将调用此模块；<br><br>**任务布置**<br>课后任务：尝试调整线程池的max_workers参数（如5、10、20），测试不同线程数对性能的影响，思考最优值。 | **回顾反思**<br>总结并发编程的关键点，明确本模块在项目中的"性能优化"作用；<br><br>**接收任务**<br>记录课后任务，理解这是对并发性能调优的探索性实验。 | 通过总结强化知识结构；通过模块集成保持项目连贯性；课后任务引导学生探索并发参数优化，培养实验精神。 |

## 板书设计

```
多线程并发采集架构

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