4. 分支和循环:if判断语句、运算符、if-else语句、while循环、for循环、break、continue
好,咱们今天聊聊控制流。说白了,就是让程序学会「动脑子」和「反复干活」。没有这两个东西,代码就是一潭死水,从上往下跑一遍就结束了。我刚开始学编程时,觉得这玩意儿简单,后来在CUDA里写分支,才发现坑有多深。嗯,咱们一步步来。
4.1 if判断语句:让代码学会做选择
if 语句,就是「如果……就……」。Python 里写起来很自然:
temperature = 38
if temperature > 37.5:
print("体温偏高,建议休息")
注意看,条件后面有个冒号,下一行要缩进。这是 Python 的规矩,少一个空格都不行。我在项目中遇到过有人把 if 和后面的条件写在同一行,结果报错找了半天——嗯,Python 不吃这套。
4.2 运算符:比较和逻辑
写条件判断,离不开运算符。咱们分两类说。
比较运算符:
| 运算符 | 含义 | 示例 |
|---|---|---|
| == | 等于 | a == b |
| != | 不等于 | a != b |
| > | 大于 | a > b |
| < | 小于 | a < b |
| >= | 大于等于 | a >= b |
| <= | 小于等于 | a <= b |
逻辑运算符:
| 运算符 | 含义 | 示例 |
|---|---|---|
| and | 与(两边都真才真) | a > 0 and b > 0 |
| or | 或(一边真就真) | a > 0 or b > 0 |
| not | 非(取反) | not a > 0 |
我个人习惯把复杂的条件拆开写,别堆在一行。你想想看,if a > 0 and b < 10 or c == 5 and not d 这种代码,三天后你自己都看不懂。我曾经在调试一个 CUDA 核函数时,就是因为条件写得太长,导致 warp 内线程分支严重,性能直接腰斩。后来拆成几个小 if,清爽多了。
4.3 if-else语句:二选一
有选择,就有备选。if-else 就是「如果……否则……」:
score = 85
if score >= 60:
print("及格了")
else:
print("没及格")
还可以用 elif 做多分支:
if score >= 90:
grade = "优秀"
elif score >= 80:
grade = "良好"
elif score >= 60:
grade = "及格"
else:
grade = "不及格"
4.4 while循环:只要条件成立,就一直干
while 循环,说白了就是「只要……就一直做……」。比如:
count = 0
while count < 5:
print(f"第 {count+1} 次循环")
count += 1
这里有个关键点:循环体内一定要有改变条件的语句,否则就是死循环。我见过有人写 while True 然后忘了加 break,程序直接卡死。嗯,Ctrl+C 都救不了你。
在 CUDA 里,while 循环用得不多,因为 GPU 擅长的是大量并行线程,每个线程做简单的事。但有时候,比如在实现归约算法时,while 循环是少不了的。我记得有一次写一个动态并行度的算法,while 循环的条件里用到了线程 ID 和全局变量,调试起来那叫一个酸爽。
4.5 for循环:遍历一切
for 循环是 Python 里最常用的循环。它用来遍历一个可迭代对象:
# 遍历列表
fruits = ["苹果", "香蕉", "橘子"]
for fruit in fruits:
print(fruit)
# 遍历范围
for i in range(5):
print(i) # 输出 0 到 4
# 遍历字典
scores = {"张三": 90, "李四": 85}
for name, score in scores.items():
print(f"{name}: {score}")
range() 函数很常用,它有三个参数:start、stop、step。比如 range(1, 10, 2) 会生成 1, 3, 5, 7, 9。我个人习惯用 range 来写固定次数的循环,比 while 更安全,因为不会忘记加计数器。
4.6 break和continue:控制循环的节奏
这两个关键字,就像循环里的「刹车」和「跳过」。
- break: 立即跳出整个循环,不再执行后续迭代。
- continue: 跳过当前迭代的剩余部分,直接进入下一次迭代。
看个例子:
# break 示例:找到第一个大于 50 的数就停
numbers = [10, 30, 55, 20, 80]
for num in numbers:
if num > 50:
print(f"找到了:{num}")
break
# continue 示例:跳过所有偶数
for i in range(10):
if i % 2 == 0:
continue
print(i) # 只输出奇数
我曾经在写一个 CUDA 核函数时,需要跳过某些不符合条件的线程。当时用了 continue,结果发现 warp 内的线程还是全部执行了——因为 GPU 的 warp 是 SIMT 模型,所有线程执行相同的指令,只是通过掩码来控制哪些线程「有效」。所以,在 GPU 上滥用 continue 和 break 反而可能降低性能。嗯,这个坑我踩过。
4.7 实战小技巧:循环与分支的配合
实际项目中,分支和循环经常一起用。比如,从一堆数据里筛选出符合条件的:
data = [12, 45, 78, 23, 56, 89, 34]
filtered = []
for value in data:
if value > 50:
filtered.append(value)
print(filtered) # 输出 [78, 56, 89]
这种模式在数据处理中太常见了。在 CUDA 里,类似的逻辑可以用并行规约或 stream compaction 来实现,但原理是一样的——先判断,再收集。
好了,这一章的内容就这些。分支和循环是编程的骨架,没有它们,代码就是一具空壳。下一章咱们聊聊函数,让代码真正「活」起来。