先说简单结论:
8.5.2 1633 microseconds per iteration # foreach 3170 microseconds per iteration # for 2494 microseconds per iteration # foreach + expr 2934 microseconds per iteration # foreach + lindex 3777 microseconds per iteration # foreach + expr + lindex 3211 microseconds per iteration # while
再上代码:
puts [info patch] lassign $argv COUNT set chars [split [string repeat x 4096] ""] proc measure [list name body "N $COUNT"] { set time [lindex [uplevel [list time $body]] 0] puts [format "%8d microseconds per iteration # %s" $time $name ] } measure "foreach" { set n 0 set N 4096 foreach c $chars { set t $c incr n } } measure "for" { set n 0 set N 4096 for {set n 0 ; set N 4096} {$n<$N} {incr n} { set c [lindex $chars $n] set t $c } } measure "foreach + expr" { set n 0 set N 4096 foreach c $chars { expr {$n<$N} set t $c incr n } } measure "foreach + lindex" { set n 0 set N 4096 foreach c $chars { set c [lindex $chars $n] set t $c incr n } } measure "foreach + expr + lindex" { set n 0 set N 4096 foreach c $chars { expr {$n<$N} set c [lindex $chars $n] set t $c incr n } } measure "while" { set n 0 set N 4096 while {$n<$N} { set c [lindex $chars $n] set t $c incr n } }
这俩个差别只是在tcl里面吗?在其他脚本语言是不是也是这样?不过这个判断在其他脚本语言里面都存在,那么应该是一样的。
8.5.17 1874 microseconds per iteration # foreach 2952 microseconds per iteration # for 2570 microseconds per iteration # foreach + expr 3025 microseconds per iteration # foreach + lindex 3708 microseconds per iteration # foreach + expr + lindex 2937 microseconds per iteration # while
8.6.1 2100 microseconds per iteration # foreach 2773 microseconds per iteration # for 2862 microseconds per iteration # foreach + expr 3162 microseconds per iteration # foreach + lindex 3804 microseconds per iteration # foreach + expr + lindex 2739 microseconds per iteration # while
从字节码(Byte Code)角度看for和foreach的分别。
ByteCode 0x0xe5b68f0, refCt 1, epoch 3, interp 0x0xe5986a0 (epoch 3) Source "\n for {set i 0} {$i<10} {incr i} {\n set v [lindex $" Cmds 5, src 70, inst 62, litObjs 6, aux 0, stkDepth 3, code/src 0.00 Exception ranges 2, depth 1: 0: level 0, loop, pc 8-35, continue 37, break 59 1: level 0, loop, pc 37-49, continue -1, break 59 Commands 5: 1: pc 0-60, src 3-68 2: pc 0-4, src 8-14 3: pc 8-35, src 40-64 4: pc 19-34, src 47-63 5: pc 37-49, src 26-31 Command 1: "for {set i 0} {$i<10} {incr i} {\n set v [lindex $val" Command 2: "set i 0" (0) push1 0 # "i" (2) push1 1 # "0" (4) storeScalarStk (5) pop (6) jump1 +45 # pc 51 Command 3: "set v [lindex $values $i]" (8) startCommand +28 1 # next cmd at pc 36 (17) push1 2 # "v" Command 4: "lindex $values $i" (19) startCommand +16 1 # next cmd at pc 35 (28) push1 3 # "values" (30) loadScalarStk (31) push1 0 # "i" (33) loadScalarStk (34) listIndex (35) storeScalarStk (36) pop Command 5: "incr i" (37) startCommand +13 1 # next cmd at pc 50 (46) push1 0 # "i" (48) incrScalarStkImm +1 (50) pop (51) push1 0 # "i" (53) loadScalarStk (54) push1 4 # "10" (56) lt (57) jumpTrue1 -49 # pc 8 (59) push1 5 # "" (61) done ByteCode 0x0xe5c66e0, refCt 1, epoch 3, interp 0x0xe5986a0 (epoch 3) Source "\n set i 0\n foreach v $values {\n incr i\n }\n" Cmds 2, src 48, inst 18, litObjs 6, aux 0, stkDepth 4, code/src 0.00 Commands 2: 1: pc 0-5, src 3-9 2: pc 6-16, src 13-46 Command 1: "set i 0" (0) push1 0 # "i" (2) push1 1 # "0" (4) storeScalarStk (5) pop Command 2: "foreach v $values {\n incr i\n }" (6) push1 2 # "foreach" (8) push1 3 # "v" (10) push1 4 # "values" (12) loadScalarStk (13) push1 5 # "\n incr i\n " (15) invokeStk1 4 (17) done
ByteCode 0x0xbaa8f60, refCt 1, epoch 15, interp 0x0xba1f680 (epoch 15) Source "\n for {set i 0} {$i<10} {incr i} {\n set v [lindex $" Cmds 5, src 70, inst 35, litObjs 6, aux 0, stkDepth 3, code/src 0.00 Exception ranges 2, depth 1: 0: level 0, loop, pc 8-17, continue 19, break 32 1: level 0, loop, pc 19-22, continue -1, break 32 Commands 5: 1: pc 0-33, src 3-68 2: pc 0-4, src 8-14 3: pc 8-17, src 40-64 4: pc 10-16, src 47-63 5: pc 19-22, src 26-31 Command 1: "for {set i 0} {$i<10} {incr i} {\n set v [lindex $val" Command 2: "set i 0" (0) push1 0 # "i" (2) push1 1 # "0" (4) storeStk (5) pop (6) jump1 +18 # pc 24 Command 3: "set v [lindex $values $i]" (8) push1 2 # "v" Command 4: "lindex $values $i" (10) push1 3 # "values" (12) loadStk (13) push1 0 # "i" (15) loadStk (16) listIndex (17) storeStk (18) pop Command 5: "incr i" (19) push1 0 # "i" (21) incrStkImm +1 (23) pop (24) push1 0 # "i" (26) loadStk (27) push1 4 # "10" (29) lt (30) jumpTrue1 -22 # pc 8 (32) push1 5 # "" (34) done ByteCode 0x0xbaa8f60, refCt 1, epoch 15, interp 0x0xba1f680 (epoch 15) Source "\n set i 0\n foreach v $values {\n incr i\n }\n" Cmds 2, src 48, inst 18, litObjs 6, aux 0, stkDepth 4, code/src 0.00 Commands 2: 1: pc 0-5, src 3-9 2: pc 6-16, src 13-46 Command 1: "set i 0" (0) push1 0 # "i" (2) push1 1 # "0" (4) storeStk (5) pop Command 2: "foreach v $values {\n incr i\n }" (6) push1 2 # "foreach" (8) push1 3 # "v" (10) push1 4 # "values" (12) loadStk (13) push1 5 # "\n incr i\n " (15) invokeStk1 4 (17) done