Implementing futures in C#
by Porges
Why?
I was bored, and it didn’t seem to have been done before, so here’s some Future action in C#.
The Code
using System; using System.IO; using System.Reflection; using System.Threading; public class Future<T> { public delegate R FutureDelegate<R>(); public Future (FutureDelegate<T> del) { Del = del; Result = del.BeginInvoke(null,null); } private FutureDelegate<T> Del; private IAsyncResult Result; private T PValue; private bool HasValue = false; private T Value { get { if (!HasValue) { if (!Result.IsCompleted) Result.AsyncWaitHandle.WaitOne(); PValue = Del.EndInvoke(Result); HasValue = true; } return PValue; } } public static implicit operator T(Future<T> f) { return f.Value; } } public static class MainClass { //This is purposely wasteful! public static ulong Fib(ulong n) { if (n > 1) { return Fib(n-1)+Fib(n-2); } else if (n == 1) return 1; else //n == 0 return 0; } //Demo using futures. public static void Main(string[] args) { Console.WriteLine("First, call synchronously."); Console.WriteLine(Fib(40)); Thread.Sleep(1000); Console.WriteLine("Next, call asynchronously."); Future<ulong> fib40 = new Future<ulong>(delegate{ return Fib(40); }); //Begins computing Fib(40) at this point... Thread.Sleep(1500); Console.WriteLine("Note that we can do other things in the mean time, and that the thread only blocks when we ask for the value."); Console.WriteLine(fib40); //Need it now! Thread.Sleep(2000); Console.WriteLine("We can then ask for the computed value as many times as we like."); Console.WriteLine(fib40); //Already computed. } } |
Caveats
Most notably, this doesn’t do promise pipelining (and I doubt I could without some compiler magicking), so instead of nesting futures, you’ll want to seperate them out. That is; instead of:
t3 = new Future(delegate{return new Future(delegate{return x.a()}).c(new Future(delegate{return y.b()}))}); |
…you’ll want to do:
t1 = new Future(delegate{return x.a()}); t2 = new Future(delegate{return y.b()}); t3 = new Future(delegate{return t1.c(t2)}); |
…although you’d probably want to do this anyway if you don’t want to wander into The LispZone.
[...] had the thought—while browsing through some old code—that the code I used to implement futures in C# would be useful for doing things lazily, if you just moved the evaluation phase to when the value [...]
thanks a lot for this post! futures are making multi-threaded background initialization easy.
– henon
It’s worth noting that
Future<T>is now part of .NET 4.0It became Task in .NET 4 RTM
Actually this methodology will yield very poor performance in most cases, as the BeginInvoke will have to set up a complete remoting environment [yes, remoting]. See http://www.lukepuplett.com/2009/05/using-delegates-oh-for-f-sake-moment.html for details.
David: Ouch! That’s a bit nasty.