Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How well does F# perform compared to C#? [duplicate]

Tags:

performance

c#

f#

Of course both F# and C# compile to IL and the CLR JITter does most of the hard work, however I wanted to know whether there's anything implicit in the F# language or its core libraries which result in lesser performance compared to C#?

Additionally, is there anything in the use of functional programming in the .net framework that might make it slower compared to C#?

I am going to sit down and measure differences of course, as that really is the only real way to know for sure, however I just wondered whether anybody had any broad-stroke knowledge on this topic.

See Also

  • C# / F# Performance comparison
  • Is a program F# any more efficient (execution-wise) than C#?
like image 394
ljs Avatar asked Dec 23 '22 13:12

ljs


2 Answers

There is nothing intrinsic that makes one language faster than the other. They both run on the CLR and hence have roughly the same performance characteristics of any language that runs on the CLR. There are features of the respective languages though that do affect performance.

Tail recursion is a great example. If you write an F# app which heavily uses tail recursion, the compiler will attempt to rewrite it as an iterative loop removing the recursion penalty. Additionally F# uses the .tail IL op code in order to ask the CLR to remove the recursion stack penalty where possible.

It's easy to demonstrate this by translating some F# continuation samples to C# and then insert huge data sets. F# will work and C# will eventually crash.

http://blogs.msdn.com/jaredpar/archive/2008/11/13/comparing-continuations-in-c-and-f-part-3-double-wrong.aspx

But that is not necessarily a deficiency in C#. C# is not meant to be written with continuations while that is certainly the case in F#. It's in fact not surprising that writing algorithms meant for F# in C# produce not so great results.

Conversely, C# iterators are usually more efficient than F# sequence expressions. The reason is that C# iterators are very efficient state machines vs. F#'s are continuation passing.

In general though, in the abscence of threads, if you use the languages as they are intended to be used they will have similar performance characteristics.

like image 87
JaredPar Avatar answered Jan 04 '23 20:01

JaredPar


A good example is the sieve of eratosthenes.

A co-worker and I wrote similar sieves in C# and F#. The performance of the C# version was almost 10 times slower than it's functional counterpart written by my co-worker.

There were probably some inefficiencies in the C# version that could have been cleaned up, but the F# version is noticeably faster.

This sort of problem lends itself to being written in a functional language..

Hope this helps some.

Edit -

Here's one of the C# examples using similar functionality to F#'s List.Partition. I'll keep looking for the F# example. I have hundreds of projects that it could be in, it's just a matter of sorting through all of my stuff to find it (I save everything I ever experiment with, so this could be time consuming.. lol)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ListPartitionTest
{
    public static class IEnumerableExtensions
    {
        public static KeyValuePair<IEnumerable<T>, IEnumerable<T>> Partition<T>(this IEnumerable<T> items, Func<T, bool> f)
        {
            return items.Aggregate(
                new KeyValuePair<IEnumerable<T>, IEnumerable<T>>(Enumerable.Empty<T>(), Enumerable.Empty<T>()),
                (acc, i) =>
                {
                    if (f(i))
                    {
                        return new KeyValuePair<IEnumerable<T>, IEnumerable<T>>(acc.Key.Concat(new[] { i }), acc.Value);
                    }
                    else
                    {
                        return new KeyValuePair<IEnumerable<T>, IEnumerable<T>>(acc.Key, acc.Value.Concat(new[] { i }));
                    }
                });
        }
    }

    class PrimeNumbers
    {
        public int Floor { get; private set; }
        public int Ceiling { get; private set; }

        private IEnumerable<int> _sieve;

        public PrimeNumbers(int floor, int ceiling)
        {
            Floor = floor;
            Ceiling = ceiling;
        }

        public List<int> Go()
        {
            _sieve = Enumerable.Range(Floor, (Ceiling - Floor) + 1).ToList();

            for (int i = (Floor < 2) ? 2 : Floor; i <= Math.Sqrt(Ceiling); i++)
            {
                _sieve = _sieve.Where(x => (x % i != 0 && x != i));

                foreach (int x in _sieve)
                {
                    Console.Write("{0}, ", x);
                }
                Console.WriteLine();
            }

            return _sieve.ToList();
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            System.Diagnostics.Stopwatch s = new System.Diagnostics.Stopwatch();
            int floor = 1;
            int ceiling = 10;

            s.Start();
            PrimeNumbers p = new PrimeNumbers(floor, ceiling);
            p.Go();
            //foreach (int i in p.Go()) Console.Write("{0} ", i);
            s.Stop();

            Console.WriteLine("\n{0} to {1} completed in {2}", floor, ceiling, s.Elapsed.TotalMilliseconds);

            Console.ReadLine();
        }
    }
}
like image 39
Ian P Avatar answered Jan 04 '23 20:01

Ian P