TL;DR:好主意1!加速似乎被限制在 ~20%(对于大多数列表大小)。
在这个答案中,我们比较了三个不同的谓词,它们在类似@ 的数据重用方面有所不同:
list_tails([], [[]])。 % (1) like `tails/2` 由 OP 给出...
list_tails([E|Es], [[E|Es]|Ess]) :- % ....... 但有一个更好的名字 :-)
list_tails(Es,Ess)。
list_sfxs1(Es, [Es|Ess]) :- % (2) "重用,相互递归"
aux_list_sfxs1(Es,Ess)。 % "sfxs" 是 "suffixes" 的缩写
aux_list_sfxs1([],[])。
aux_list_sfxs1([_|Es], Ess) :-
list_sfxs1(Es,Ess)。
list_sfxs2([], [[]])。 %(3)“重用,直接递归”
list_sfxs2(Es0, [Es0|Ess]) :-
Es0 = [_|Es],
list_sfxs2(Es,Ess)。
为了测量运行时间,我们使用以下代码:
:-(
dif(D,
sicstus),
current_prolog_flag(
dialect,D)
;
use_module(
library(between))
)。
run_benchs(P_2s,P_2,L,N,T_ms):-
between(1, 6, I),
L
is 10
^I,
N 是 10^(8-I),
length(Xs, L),
member(P_2, P_2s),
garbage_collect,
call_walltime(run_bench_core(P_2,Xs,N),
T_ms)。
run_bench_core(P_2, Xs, N) :-
在(1,N,_)之间,
call(P_2, Xs, _),
false。
run_bench_core(_, _, _)。
为了测量wall-time2,我们使用call_@987654337@/2——call_time/2 的变体:
call_walltime(G, T_ms) :-
statistics(
walltime, [T0|_]),
G,
统计数据(墙上时间,[T1|_]),
T_ms 是 T1 - T0。
让我们将上面的代码变体进行测试...
- ...使用不同的列表长度
L...
- ...并多次运行每个测试
N(以获得更好的准确性)。
首先,我们使用swi-prolog 7.3.14 版(64 位):
?- run_benchs([list_sfxs1,list_sfxs2,list_tails], P_2, L, N, T_ms)。
P_2 = list_sfxs1,L*N = 10*10000000,T_ms = 7925
; P_2 = list_sfxs2,L*N = 10*10000000,T_ms = 7524
; P_2 = list_tails,L*N = 10*10000000,T_ms = 6936
;
P_2 = list_sfxs1,L*N = 100*1000000,T_ms = 6502
; P_2 = list_sfxs2,L*N = 100*1000000,T_ms = 5861
; P_2 = list_tails,L*N = 100*1000000,T_ms = 5618
;
P_2 = list_sfxs1,L*N = 1000*100000,T_ms = 6434
; P_2 = list_sfxs2,L*N = 1000*100000,T_ms = 5817
; P_2 = list_tails,L*N = 1000*100000,T_ms = 9916
;
P_2 = list_sfxs1,L*N = 10000*10000,T_ms = 6328
; P_2 = list_sfxs2,L*N = 10000*10000,T_ms = 5688
; P_2 = list_tails,L*N = 10000*10000,T_ms = 9442
;
P_2 = list_sfxs1,L*N = 100000*1000,T_ms = 10255
; P_2 = list_sfxs2,L*N = 100000*1000,T_ms = 10296
; P_2 = list_tails,L*N = 100000*1000,T_ms = 14592
;
P_2 = list_sfxs1,L*N = 1000000*100,T_ms = 6955
; P_2 = list_sfxs2,L*N = 1000000*100,T_ms = 6534
; P_2 = list_tails,L*N = 1000000*100,T_ms = 9738。
然后,我们使用sicstus-prolog 4.3.2 版(64 位)重复上一个查询3:
?- run_benchs([list_sfxs1,list_sfxs2,list_tails], P_2, L, N, T_ms)。
P_2 = list_sfxs1,L*N = 10*10000000,T_ms = 1580
; P_2 = list_sfxs2,L*N = 10*10000000,T_ms = 1610
; P_2 = list_tails,L*N = 10*10000000,T_ms = 1580
;
P_2 = list_sfxs1,L*N = 100*1000000,T_ms = 710
; P_2 = list_sfxs2,L*N = 100*1000000,T_ms = 750
; P_2 = list_tails,L*N = 100*1000000,T_ms = 840
;
P_2 = list_sfxs1,L*N = 1000*100000,T_ms = 650
; P_2 = list_sfxs2,L*N = 1000*100000,T_ms = 660
; P_2 = list_tails,L*N = 1000*100000,T_ms = 740
;
P_2 = list_sfxs1,L*N = 10000*10000,T_ms = 620
; P_2 = list_sfxs2,L*N = 10000*10000,T_ms = 650
; P_2 = list_tails,L*N = 10000*10000,T_ms = 740
;
P_2 = list_sfxs1,L*N = 100000*1000,T_ms = 670
; P_2 = list_sfxs2,L*N = 100000*1000,T_ms = 650
; P_2 = list_tails,L*N = 100000*1000,T_ms = 750
;
P_2 = list_sfxs1,L*N = 1000000*100,T_ms = 12610
; P_2 = list_sfxs2,L*N = 1000000*100,T_ms = 12560
; P_2 = list_tails,L*N = 1000000*100,T_ms = 33460。
总结:
-
alias-thingy 可以并且确实提高了性能。
- 在上述测试中,与 SWI-Prolog 相比,SICStus Prolog jit4 提供 10 倍加速!
脚注 1: 为什么将(@)/2 放在规则头中?
以非idiomatic Prolog 代码结束?
脚注 2: 我们对总运行时间感兴趣。为什么?因为垃圾收集成本随着数据量的增大而显现!
脚注 3:为了便于阅读,已对答案序列进行了后处理。
脚注 4: 自release 4.3.0 起可用。当前的目标架构包括IA-32和AMD64。