question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Discussion: Memoization solution

See original GitHub issue

As @SamyPesse and I are investigating performances issues, we are having a look at the current memoization implementation.

We have noticed for example that the sole memoization of findDescendantDeep is taking up to 30% of the execution time during normalization calls. Several reasons:

  1. findDescendantDeep is recursive, and gets called many times
  2. its argument is a function, and we always pass an arrow function to it (unique reference every time), which prevent any cache hit
  3. the cache grows indefinitely, and a lot of time is spent looking for cached results in the underlying Immutable.Map with no benefit (the calls to hasIn and setIn account for the mentioned 30%).

Of course, we are going to improve the case of findDescendantDeep (and similarly findDescendant). But this also opens up a new topic: the way we memoize methods. Currently, we use an in-house solution using an Immutable.Map cache. But should we consider using a popular implementation, like memoizee and such? It can bring:

  • Better performances
  • Cache management, with LRU limits for example

@ianstormtaylor what’s your opinion?

Issue Analytics

  • State:closed
  • Created 7 years ago
  • Comments:7 (3 by maintainers)

github_iconTop GitHub Comments

1reaction
Soreinecommented, Nov 2, 2016

Tying caches to each Node instance is a good idea, I had not realized that.

For arrows, it’s not that easy. Take for example the case of getDescendant (which is itself memoized). Its implementation is simply return this.findDescendantDeep(node => node.key == key). We can’t make the arrow a static function because we need the key value in the closure.

For now, I will keep the iterator methods unmemoized. And I’ll make sure we have specific memoized methods for cases like this. Continuing on the example of getDescendant, I will rewrite getDescendant to be recursively memoized on its own:

  /**
   * Get a descendant node by `key`.
   *
   * @param {String} key
   * @return {Node or Null} node
   */

  getDescendant(key) {
    key = Normalize.key(key)
    return this._getDescendant(key)
  },

  // This one is memoized
  _getDescendant(key) {
    let descendantFound = null

    const found = this.nodes.find(node => {
      if (node.key === key) {
        return node
      } else if (node.kind !== 'text') {
        descendantFound = node._getDescendant(key)
        return descendantFound
      } else {
        return false
      }
    })

    return descendantFound || found
  }
0reactions
ianstormtaylorcommented, Nov 17, 2016

Closing, since I think we came to a solution here.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Memoization (1D, 2D and 3D) - GeeksforGeeks
One of the easier approaches to solve most of the problems in DP is to write the recursive code at first and then...
Read more >
MEMOIZATION WITH EXPLANATION - LeetCode Discuss
Level up your coding skills and quickly land a job. This is the best place to expand your knowledge and get prepared for...
Read more >
Memoization · Discussion #2412 · timber/timber - GitHub
In Timber, we already have quite a few places where we use memoization, but always with a custom setup: Timber::context() caches the global...
Read more >
EECS 311: Dynamic Programming Resources
Memoization is a classic programming technique, easy to implement in some languages, like Lisp and Python, a little harder in strongly typed languages...
Read more >
Memoization in Dynamic Programming Through Examples
Dynamic programming is a technique for solving problems, whose solution can be expressed recursively in terms of solutions of overlapping sub-problems.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found