10

What is the name of the following method/technique (I'll try to describe the best I could, background on "memoization" is probably needed to understand why this technique can be very useful):

You start some potentially lenghty asynchronous computation and you realize that an identical computation has already been started but is not done yet and you "piggyback" on the first computation. Then when the first computation ends, it issues not one but two callbacks.

The goal is to not needlessly start a second computation because you know that there's already an identical computation running.

Note that altough not entirely dissimilar, I'm not looking for the particular case of caching that "memoization" is: memoization is when you start a computation and find a cached (memoized) result of that same computation that is already done that you can reuse.

Here I'm looking for the name of the technique that is in a way a bit similar to memoization (in that it is can be useful for some of the same reasons that memoization is a useful technique), except that it reuses the result of the first computation even if the first computation is not done yet at the time you issue the second computation.

I've always called that technique "piggybacking" but I don't know if this is correct.

I've actually used this more than once as some kind of "memoization on steroids" and it came very handy.

I just don't know what the name of this (advanced ?) technique is.

EDIT

Damn, I wanted to comment on epatel's answer but it disappeared. epatel's answer gave me an idea, this technique could be called "lazy memoization" :)

cocotwo
  • 1,285
  • 2
  • 13
  • 19
  • @Robert Harvey: googling on "Thread cancellation" :) hummm... The problem I think is that thread cancellation has a lot of meaning and that here depending on the implementation you may even not be starting at all the second lenghty asynchronous thread because you're directly piggybacking on the other one. – cocotwo Mar 04 '10 at 23:27
  • 1
    I have seen "piggybacking" used in a different context but for the same idea: the newcomer takes advantage of the overhead that has already been (or is being) paid by someone else. Don't let that prevent you to find or define a work particular to your context. – Pascal Cuoq Mar 04 '10 at 23:34
  • @Pascal Cuoq: in different context but in software programming you mean? I know I've seen this somewhere, but a long time ago. I just can't remember where I learned that. – cocotwo Mar 04 '10 at 23:38
  • @Dan: +1 for the excellent tag edit :) – cocotwo Mar 04 '10 at 23:39
  • 3
    A lazy evaluated synchonized future cache! – Tanzelax Mar 04 '10 at 23:41
  • 1
    Could it be Partial memoization? You can find a few technical papers referencing to it through google search – Fadrian Sudaman Mar 04 '10 at 23:41
  • @Fadrian: +1 on your comment. I've got to read the papers more carefully but at first sight what I described above may be a simplified case of *"partial memoization"*. Not sure yet but +1 anyway, I sure didn't know about "partial memoization" even tough I'm familiar with memoization. – cocotwo Mar 04 '10 at 23:51
  • If I were in a bad mood, I'm sure I could get somebody angry by just calling it "Intelligent Design". – Jerry Coffin Mar 05 '10 at 01:19
  • @Jerry: Yeah, it reads like "lazy evaluation with proper synchronization handling" to me rather than any crazy technique that needs a cool name... but then, there's a lot of other simple concepts and techniques that we give distinct names to as well. – Tanzelax Mar 05 '10 at 01:48
  • @Tanzelax: exactly... I was just wondering if there was a name for this and why I've always been calling this "piggybacking". Btw the question came to me when I was documenting that part of my code: I started to write that I was 'piggybacking' then was wondering if the others would know what I was talking about :) – cocotwo Mar 05 '10 at 13:18

4 Answers4

4

This is just memoization of futures.

Normal "eager" memoization works like this:

f_memo(x):
  critical_section:
    if (exists answers(f,x))
      return answers(f,x)
    else
      a = f(x)
      answers(f,x) = a
      return a

Now if f(x) returns futures instead of actual results, the above code works as is. You get the piggyback effect, i.e. like this:

  1. First thread calls f(3)
  2. There is no stored answer for f(3), so in the critical section there's a call to f(3). f(3) is implemented as returning a future, so the 'answer' is ready immediately; 'a' in the code above is set to the future F and the future F is stored in the answers table
  3. The future F is returned as the "result" of the call f(3), which is potentially still ongoing
  4. Another thread calls f(3)
  5. The future F is found from the table, and returned immediately
  6. Now both threads have handle to the result of the computation; when they try to read it, they block until the computation is ready---in the post this communication mechanism was mentioned as being implemented by a callback, presumeably in a context where futures are less common
Antti Huima
  • 25,136
  • 3
  • 52
  • 71
  • Exactly what I thought reading the question. Futures are not so much used yet they are so promising (if you get cheap threads like go coroutines). – Matthieu M. Mar 05 '10 at 10:28
  • @antti.huima: I guess it depends on what you prefer: to have two threads (or more) blocked on waiting a future (which is Matthieu M hints to: you need cheap threads) or to poll a future's 'is done' or to use instant callback notification upon completion. I agree that when it's implemented using future it's a "memoization of futures" but future are not the only way to do it. I'm using something more like a "ProgressOrResultHandable" callback, which from a message passing point of view is IMHO much cleaner than future. No blocking, no time out, no polling. Just instant callback notification. – cocotwo Mar 05 '10 at 13:15
  • @cocotwo callbacks are indeed cleaner if you are programming in an event-driven fashion. Futures are used when threads and parallelism are common and they are useless otherwise. For example, consider: for(i=0;i<100;i++) pages[i]=fetch_web_page(url[i]); if fetch_web_page spawns a thread and returns a future, this automatically parallelizes without any further programming constructs! In practice, the futures would support querying if they are ready, i.e. later you could ask is_ready(pages[i]) for progress reporting without blocking; you block when you actually access the results. – Antti Huima Mar 05 '10 at 18:13
2

Sounds like a future: http://en.wikipedia.org/wiki/Future_%28programming%29

ergosys
  • 47,835
  • 5
  • 49
  • 70
  • @ergosys: it's more complicated than a Future. A future is useful, for example, to display either a progress bar or the result of a computation. Here's it's having a second computation "piggyback" *on the Future of the first computation*. – cocotwo Mar 04 '10 at 23:33
2

In some contexts, I've heard this called "Request Merging".

caf
  • 233,326
  • 40
  • 323
  • 462
1

Sounds a little like Lazy Evaluation, but not exactly...

epatel
  • 45,805
  • 17
  • 110
  • 144