Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 4586742
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: May 21, 20262026-05-21T21:40:55+00:00 2026-05-21T21:40:55+00:00

Years ago, I solved a problem via dynamic programming: https://www.thanassis.space/fillupDVD.html The solution was coded

  • 0

Years ago, I solved a problem via dynamic programming:

https://www.thanassis.space/fillupDVD.html

The solution was coded in Python.

As part of expanding my horizons, I recently started learning OCaml/F#. What better way to test the waters, than by doing a direct port of the imperative code I wrote in Python to F# – and start from there, moving in steps towards a functional programming solution.

The results of this first, direct port… are disconcerting:

Under Python:

  bash$ time python fitToSize.py
  ....
  real    0m1.482s
  user    0m1.413s
  sys     0m0.067s

Under FSharp:

  bash$ time mono ./fitToSize.exe
  ....
  real    0m2.235s
  user    0m2.427s
  sys     0m0.063s

(in case you noticed the “mono” above: I tested under Windows as well, with Visual Studio – same speed).

I am… puzzled, to say the least. Python runs code faster than F# ? A compiled binary, using the .NET runtime, runs SLOWER than Python’s interpreted code?!?!

I know about startup costs of VMs (mono in this case) and how JITs improve things for languages like Python, but still… I expected a speedup, not a slowdown!

Have I done something wrong, perhaps?

I have uploaded the code here:

https://www.thanassis.space/fsharp.slower.than.python.tar.gz

Note that the F# code is more or less a direct, line-by-line translation of the Python code.

P.S. There are of course other gains, e.g. the static type safety offered by F# – but if the resulting speed of an imperative algorithm is worse under F# … I am disappointed, to say the least.

EDIT: Direct access, as requested in the comments:

the Python code: https://gist.github.com/950697

the FSharp code: https://gist.github.com/950699

  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-05-21T21:40:55+00:00Added an answer on May 21, 2026 at 9:40 pm

    Dr Jon Harrop, whom I contacted over e-mail, explained what is going on:

    The problem is simply that the program has been optimized for Python. This is common when the programmer is more familiar with one language than the other, of course. You just have to learn a different set of rules that dictate how F# programs should be optimized…
    Several things jumped out at me such as the use of a “for i in 1..n do” loop rather than a “for i=1 to n do” loop (which is faster in general but not significant here), repeatedly doing List.mapi on a list to mimic an array index (which allocated intermediate lists unnecessarily) and your use of the F# TryGetValue for Dictionary which allocates unnecessarily (the .NET TryGetValue that accepts a ref is faster in general but not so much here)

    … but the real killer problem turned out to be your use of a hash table to implement a dense 2D matrix. Using a hash table is ideal in Python because its hash table implementation has been extremely well optimized (as evidenced by the fact that your Python code is running as fast as F# compiled to native code!) but arrays are a much better way to represent dense matrices, particularly when you want a default value of zero.

    The funny part is that when I first coded this algorithm, I DID use a table — I changed the implementation to a dictionary for reasons of clarity (avoiding the array boundary checks made the code simpler – and much easier to reason about).

    Jon transformed my code (back :-)) into its array version, and it runs at 100x speed.

    Moral of the story:

    • F# Dictionary needs work… when using tuples as keys, compiled F# is slower than interpreted Python’s hash tables!
    • Obvious, but no harm in repeating: Cleaner code sometimes means… much slower code.

    Thank you, Jon — much appreciated.

    EDIT: the fact that replacing Dictionary with Array makes F# finally run at the speeds a compiled language is expected to run, doesn’t negate the need for a fix in Dictionary’s speed (I hope F# people from MS are reading this). Other algorithms depend on dictionaries/hashes, and can’t be easily switched to using arrays; making programs suffer “interpreter-speeds” whenever one uses a Dictionary, is arguably, a bug. If, as some have said in the comments, the problem is not with F# but with .NET Dictionary, then I’d argue that this… is a bug in .NET!

    EDIT2: The clearest solution, that doesn’t require the algorithm to switch to arrays (some algorithms simply won’t be amenable to that) is to change this:

    let optimalResults = new Dictionary<_,_>()
    

    into this:

    let optimalResults = new Dictionary<_,_>(HashIdentity.Structural)
    

    This change makes the F# code run 2.7x times faster, thus finally beating Python (1.6x faster). The weird thing is that tuples by default use structural comparison, so in principle, the comparisons done by the Dictionary on the keys are the same (with or without Structural). Dr Harrop theorizes that the speed difference may be attributed to virtual dispatch: “AFAIK, .NET does little to optimize virtual dispatch away and the cost of virtual dispatch is extremely high on modern hardware because it is a “computed goto” that jumps the program counter to an unpredictable location and, consequently, undermines branch prediction logic and will almost certainly cause the entire CPU pipeline to be flushed and reloaded”.

    In plain words, and as suggested by Don Syme (look at the bottom 3 answers), “be explicit about the use of structural hashing when using reference-typed keys in conjunction with the .NET collections”. (Dr. Harrop in the comments below also says that we should always use Structural comparisons when using .NET collections).

    Dear F# team in MS, if there is a way to automatically fix this, please do.

    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

Nine years ago when I started to parsing HTML and free text with Perl
I haven't used Access since high school, years ago. What kind of problem does
2 years ago i was using mysql security providers [membership,role] from code-project article: http://www.codeproject.com/KB/database/mysqlmembershipprovider.aspx
Years ago when I was working with C# I could easily create a temporary
Years ago when I was starting a small development project, the other developers and
Years ago I released a program called Banshee Screamer Alarm and at the time
Two years ago, we shipped a multi-gigabyte Windows application, with lots of video files.
Some years ago I was told about a study into code reuse. Apparently it
Many years ago I remember a fellow programmer counselling this: new Some::Class; # bad!
Almost 5 years ago Joel Spolsky wrote this article, The Absolute Minimum Every Software

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.