glycerine / zygomys

Zygo is a Lisp interpreter written in 100% Go. Central use case: dynamically compose Go struct trees in a zygo script, then invoke compiled Go functions on those trees. Makes Go reflection easy.
https://github.com/glycerine/zygomys/wiki
BSD 2-Clause "Simplified" License
1.71k stars 81 forks source link

Fibonacci speed, rather slow #34

Closed jkleiser closed 5 years ago

jkleiser commented 5 years ago

I compared the speed of zygo running a simple recursive Fibonacci function with the speed of similar code ran in "Nukata Lisp" (https://github.com/nukata/lisp-in-dart), and I was disappointed to see that zygo seemed to be more than 35 (maybe 70?) times slower than Nukata Lisp at this. The Fibonacci function I used for zygo was this:

(defn fib [n]
  (cond (< n 3)
    1
    (+ (fib (- n 1)) (fib (- n 2)))))

The code I used for Nukata Lisp was this:

(defun fib (n)
  (if (< n 3)
    1
    (+ (fib (- n 1)) (fib (- n 2)))))

I did the timing of zygo using the 'timeit' function, and each time I did it, the value 514229 was printed twice, with some delay between. This is what happened:

zygo> (defn fib [n] (cond (< n 3) 1 (+ (fib (- n 1)) (fib (- n 2)))))
zygo> (timeit (fn [] (println (fib 29))))
514229
514229
ran 1 iterations in 17.000692 seconds
average 17.000692 seconds per run

However, if I put the Fibonacci function and (println (fib 29)) into a file fib.zy, then I could do this:

$ time zygo fib.zy 
514229

real    0m8.245s
user    0m16.245s
sys 0m1.917s

Some of the difference in speed between zygo and Nukata Lisp may be due to the fact that the number of features and built-in functions implemented in Nukata Lisp is very limited compared to the numerous features and functions in zygo. On the other hand, zygo is written in Go, while this Nukata Lisp is written in Dart.

glycerine commented 5 years ago

Hi Jon! Yes, this is all true. Interpretted zygo is not fast. Zygo’s reason for being is to run compiled Go code on trees at compiled Go speed. Where the trees have composed in zygo dynamically, then converted to Go struct trees by reflection.

If you don’t care about tight integration with Go and running compiled Go, there are many faster choices.

glycerine commented 5 years ago

Closing this out, there's nothing to do.

For faster (but still slower than compiled Go), you might try my later project, https://github.com/gijit/gi as it will be faster. It translates Go into Lua and then runs it on a LuaJIT VM. It also allows embedding within Go and fairly close work with Go. While it does require CGO, I've made it work on OSX, Windows, and Linux.

glycerine commented 5 years ago

additional alternatives:

https://github.com/cosmos72/gomacro - if you are okay with an MPL license; and

https://github.com/go-interpreter/chezgo - another of mine, which gives you full on Chez scheme, embedded in Go using CGO. This will be much more feature-ful, mature, and more highly tuned. However conveying Go structures back and forth won't be easy, if even possible.