SWI-Prolog中按;键后CPU占用率达100%的原因咨询
为什么非尾递归阶乘按
;后CPU跑满? 先看你写的阶乘代码:
f(0, F) :- F is 1. f(N, F) :- N > 0, N1 is N - 1, f(N1, F1), F is N * F1.
当你查询f(50000, Result)时,Prolog会顺着递归链直接调用到f(0,1),再逐层返回计算乘积,很快就能得到结果——这是因为它走的是一条确定的递归路径,没有多余分支需要探索。
但按下;要求查找下一个解时,Prolog会启动回溯机制,从最底层的递归调用开始,逐个检查每个回溯点是否存在其他可能的解:
- 首先回到最底层的
f(0,F),尝试匹配第二个子句,但0>0不成立,这个点没有其他解; - 接着回溯到上一层的
f(1,F1),此时已经通过第一个分支得到结果,现在要检查有没有其他方式满足f(1,F1)——也就是再次尝试第二个子句,但走的还是同样的路径:N1=0,调用f(0,F1),但f(0,F1)已经确认没有其他解,所以这个点也没有新解; - 以此类推,Prolog会沿着50000层的递归链逐层回溯,每一层都要重复检查子句条件、确认没有其他分支。整个过程没有实际的新计算,但50000层的回溯操作累加起来,就会导致CPU跑满,需要很长时间才能完成所有回溯点的检查,最终确认没有其他解。
简单说:你的非尾递归结构给每一层调用都留下了“有没有其他解”的回溯标记,按;后Prolog必须逐个验证这些标记,虽然最终都没有新解,但这么多层的操作需要大量CPU时间。如果换成尾递归版本,因为尾递归会复用栈帧,不会留下这么多回溯点,按;后就能很快确认没有其他解。
内容的提问来源于stack exchange,提问作者Avrohom Yisroel
相关产品推荐
相关产品推荐

