| By Chad Albrecht | Article Rating: |
|
| May 10, 2006 10:00 AM EDT | Reads: |
18,072 |
Listing 5 defines a module called pb and creates a prototype for the CalculatePiDigits function. To a C# developer this looks really strange! It's essentially saying CalculatePiDigits takes an integer as an input and returns a string. The strangeness will continue as we look at the meat of the calculation class. But before I got into full-fledged F# development, I wanted to make sure it would run on the grid. I added the code in Listing 6 to pb.fs as a test.
From Listing 6, we see that we begin by declaring the implementation of module pb followed by opening System. Opening in F# is equivalent to the using statement in C#. Next we define a function CalculatePiDigits using the let syntax. CalculatePiDigits will explicitly take an integer, n, as an input argument and implicitly return a string. This is a key and unique feature of F#, the ability to mix explicit and implicit typing.
To call the F# code contained in the pb module, I modified the Start method of the PiCalcGridThread class and included the Microsoft.FSharp namespace statement in Listing 7.
After compiling the solution and running it, everything appeared to work but it showed Pi as 3 with no numbers after the decimal. A little digging into the Alchemi user guide and the log file revealed that my F# based plouffe_bellard.dll wasn't being sent to the executor. To overcome that I had to add the lines in Listing 8 to the startup code.
Adding file dependencies to the GApplication manifest let Alchemi distribute these files with the tasks. As a result the F# code can run on remote machines. Alternatively you can specify the standalone compiler option to compile these into a single DLL. If you use this option the dependency code looks like Listing 9. After this was done, the job ran. Figure 4 shows the result of the first test run.
I could now move on to rewriting the C# Plouffe-Bellard calculation class in F#. As a result of a lot of reading and instant messaging with optionsScalper, the first working F# Plouffe-Bellard module is in Listing 10.
To compare the differences between C# and F# take a look at Listing 2 and Listing 10. As you can see the use of F# mutables helps in this endeavor immensely! Mutables in F# are modifiable, by reference, values that are implicitly dereferenced. Mutables use the local mutation assignment operator: id exp r. As you become a more experienced F# developer, you'll find yourself using mutables less. However, mutables are indispensable when doing direct C# to F# conversion as you'll see.
Going All In
With the basic Plouffe-Bellard
algorithm working well in F#, it was time to get rid of the C# all
together. I began by converting the C# GThread over to F# by adding the
definition to the pb.fsi file and the implementation to pb.fs as shown
in Listing 11 and 12.
You'll see the similarities between Listing 4 and Listing 12. The differences include:
- Inheritance technique
- Constructor implementation
- Use of base class
- Method overloading technique
Constructors are implemented using the new keyword and can be defined as using the keyword to access the base class. The use of the base class is required to implement method overloading using the override keyword.
Finally, I implemented the main code in F# in Listing 13.
In this code segment, some of the issues I ran into with F# are:
- Hooking into events
- Exception handling
- Type up and down casting
An example would be type car is derived from type vehicle then car needs to be up cast to a vehicle and vehicle needs to be down cast to a car.
More Advanced F#
F# was originally written by Dr.
Don Syme of Microsoft Research. Dr. Syme still maintains F# and plays
an active part of the F# community. After discussing this article and
its code with him, he suggested some changes. The changes highlight
some of the advantages of using F#. In particular he suggested:
- Use for-loops instead of while loops
- Try to remove mutables
- Try to stick with F# convention and use lower case variable names for most letbound variables and arguments
- Make your classes smaller and more reusable. Classes rarely need to capture variables explicitly
The hardest thing for me to adapt to has been the use of let-bound functions. While it reminds me of the use of macros in other languages, I'm still not used to seeing them inline with the rest of the code. You can see an example of this in Listing 14. The declaration of check in the is_prime function took me a while to understand.
Performance Comparison
One of the most interesting
parts of this process was examining the performance differences between
C# and F#. My initial assumption was that the F# code had to be slower.
This, in fact, is not the case. In a starting benchmark, I wanted to
examine the differences in performance of the Plouffe-Bellard
calculation.
Without any optimization the F# implementation took 453 ms. C# finished up in 62 ms. Turning optimization on caused the C# results to drop to 46 ms. And, most shocking of all, the F# was dead even at 46 ms! Apparently, the F# compiler does an excellent job optimizing the code. Continuing on, I ran the entire C# and F# grid applications against one another. Without any optimization the C# code took 3.9 seconds to calculate 100 digits of pi while F# only took 2.8 seconds. Optimizing this application showed that F# would finish in 1.5 seconds while C# would not complete any faster than 2.6 seconds. (Table 1)
A look at the IL showed the reason for the difference. From the beginning of Listing 10 you can see the use of the inline keyword, not available in C#, this lets F# squeeze out a little more performance. If you're not familiar with the concept of inline functions, let me explain. Each time a function is called arguments need to be pushed onto the stack or stored in registers. When the function is done results need to be pushed onto the stack, all this takes time. The cost of these calls can be avoided by moving the function into the body of the calling code. The C# compiler doesn't support the inlining, instead, it relies on the JIT to do this. Here's a simplified list of heuristics that the JIT uses to decide if a method should be inlined:
- Methods that are greater than 32 bytes of IL won't be inlined.
- Virtual functions aren't inlined.
- Methods that have complex flow control won't be in-lined. Complex flow control is any flow control other than if/then/else; in this case, switch or while.
- Methods that contain exception-handling blocks aren't inlined, though methods that throw exceptions are still candidates for inlining.
- If any of the method's formal arguments are structs, the method won't be inlined.
Conclusion
The intent of this article was to
provide you with a glimpse into some exciting new technologies. I've
presented some strategies for converting C# to F#, implementation of
algorithms in F# and corresponding performance results. While
discussing this article with a number of colleagues, it's obvious that
there are a lot of applications for the coupling of these technologies.
Further work might include the integration of grid computing into the
F# language as well as the F# interactive console. Hopefully this
article will inspire you to include F# and grid computing in your list
of tools available to attack future problems.
Resources
- Fabrice Bellard, "Computation of the n'th digit of pi in any base in O(n^2)," January 1997.
- Simon Plouffe, "On the computation of the n'th decimal digit of various transcendental numbers," November 1996.
- Akshay Luther, Krishna Nadiminti, Rajkumar Buyya, "Alchemi: A .NET-based Enterprise Grid System and Framework - User Guide for Alchemi 1.0," July 2005.
- Microsoft Research-F# Web site, research.microsoft.com/fsharp/fsharp.aspx
- Dr. Don Syme's Blog, blogs.msdn.com/dsyme/
- Alchemi Web site, www.alchemi.net/
- optionsScalper's Web site, http://cs.jjbresearch.org/
- Fabrice Bellard's Web site, http://fabrice.bellard.free.fr/
- Simon Plouffe's Web site, www.lacim.uqam.ca/~plouffe/
- OCaml Web site, caml.inria.fr/
Published May 10, 2006 Reads 18,072
Copyright © 2006 SYS-CON Media, Inc. — All Rights Reserved.
Syndicated stories and blog feeds, all rights reserved by the author.
More Stories By Chad Albrecht
Chad Albrecht is president of EnerLinx.com, Inc.
- Kindle 2 vs Nook
- Confessions of a Ulitzer Addict
- IBM Hardware Chief, Intel VC Exec Arrested in Insider Trading Scam
- Tactical Cloud Computing Panel at 1st Annual GovIT Expo
- Ulitzer.com Named Exclusive "New Media" Sponsor of Cloud Computing Conference & Expo
- Infrastructure-as-a-Service Will Mature in 2010: Microsoft's David Chou
- Windows 7 – Microsoft’s First Step to the Cloud
- Cloud Expo and the End of Tech Recession
- Jill Tummler Singer, Deputy CIO of CIA, Keynotes at GovIT Expo
- Reality Check at the Cloud Computing Expo
- Visual Studio 2010 Is Cloud Friendly
- Fired SCO CEO Fires Back
- Kindle 2 vs Nook
- The Difference Between Web Hosting and Cloud Computing
- Ajax in RichFaces 3.3, JSF 2 and RichFaces 4
- Confessions of a Ulitzer Addict
- Wave on Ulitzer: Confessions of a Google Wave Fanboy
- IBM Hardware Chief, Intel VC Exec Arrested in Insider Trading Scam
- Cloud Computing Best Practices
- Tactical Cloud Computing Panel at 1st Annual GovIT Expo
- Ulitzer.com Named Exclusive "New Media" Sponsor of Cloud Computing Conference & Expo
- Infrastructure-as-a-Service Will Mature in 2010: Microsoft's David Chou
- Eval JavaScript in a Global Context
- Windows 7 – Microsoft’s First Step to the Cloud
- Google Maps and ASP.NET
- Crystal Reports XI & How It Has Changed
- Converting VB6 to VB.NET, Part I
- Creating Controls for.NET Compact Framework in Visual Studio 2005
- Where Are RIA Technologies Headed in 2008?
- How to Write High-Performance C# Code
- AJAX World RIA Conference & Expo Kicks Off in New York City
- Implementing Tab Navigation with ASP.NET 2.0
- i-Technology Photo Exclusive: Bill Gates & Steve Jobs In "Nerds"
- .NET Archives: Getting Reacquainted with the Father of C#
- i-Technology Viewpoint: "SOA Sucks"
- Programmatically Posting Data to ASP .NET Web Applications































