type ( Keyfunc func(...interface{}) string Memfunc func(...interface{}) interface{} Algofunc func(int) int ) func memoize(f Memfunc, kf Keyfunc) Memfunc { if kf == nil { kf = func(v ...interface{}) string { // Very naive keygen func, simply use string representation // of every param var buffer bytes.Buffer for i := 0; i < len(v); i++ { buffer.WriteString(fmt.Sprint(v[0])) buffer.WriteString(",") } return buffer.String() } } cache := make(map[string]interface{}) return func(v ...interface{}) interface{} { cachekey := kf(v) if r, ok := cache[cachekey]; ok { // Hit, return previous result return r } // Miss, call calculator r := f(v...) cache[cachekey] = r return r } }
Our object is a trivial one, its only purpose to demonstrate the speedup from the memoizing transformation. The method accepts an int argument, waits for one second and then returns the argument.
type Object struct { } func (o *Object) Say(p int) int { time.Sleep(1 * time.Second) return p }
The main function starts by executing the raw method and timing it:
func main() { var obj Object duration, res := timeThis(obj.Say, 1) fmt.Printf("Object says: %d, takes %s to do it.\n", res, duration)
Our typecasting code structure is simpler this time around because the method is not a recursive one, only typecasting is needed.
msay := func(f Algofunc) Algofunc { memsay := memoize(func(values ...interface{}) interface{} { return f(toInt(values[0])) }, nil) // Return a function that will do the neccessary typecasting return func(val int) int { return toInt(memsay(val)) } }(obj.Say) duration, res = timeThis(msay, 1) fmt.Printf("Memoized object says: %d, takes %s to do it.\n", res, duration) duration, res = timeThis(msay, 1) fmt.Printf("Memoized object says: %d, takes %s to do it.\n", res, duration) duration, res = timeThis(msay, 2) fmt.Printf("Memoized object says: %d, takes %s to do it.\n", res, duration) duration, res = timeThis(msay, 2) fmt.Printf("Memoized object says: %d, takes %s to do it.\n", res, duration) }
The results are predictable, the method takes one second to execute while the memoized version drops down to 15ms after the first execution:
Object says: 1, takes 1.001060856s to do it.
Memoized object says: 1, takes 1.001117812s to do it.
Memoized object says: 1, takes 14.71us to do it.
Memoized object says: 2, takes 1.001044387s to do it.
Memoized object says: 2, takes 14.893us to do it.
Get the source at GitHub.
No comments:
Post a Comment