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