Search icon CANCEL
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Conferences
Free Learning
Arrow right icon
F# High Performance
F# High Performance

F# High Performance: Increase your F# programming productivity and focus on performance optimization with best practices, expert techniques, and more

Arrow left icon
Profile Icon Kusumawardhono
Arrow right icon
NZ$71.99
Full star icon Full star icon Full star icon Full star icon Full star icon 5 (1 Ratings)
Paperback Jan 2017 338 pages 1st Edition
eBook
NZ$39.99 NZ$57.99
Paperback
NZ$71.99
Subscription
Free Trial
Arrow left icon
Profile Icon Kusumawardhono
Arrow right icon
NZ$71.99
Full star icon Full star icon Full star icon Full star icon Full star icon 5 (1 Ratings)
Paperback Jan 2017 338 pages 1st Edition
eBook
NZ$39.99 NZ$57.99
Paperback
NZ$71.99
Subscription
Free Trial
eBook
NZ$39.99 NZ$57.99
Paperback
NZ$71.99
Subscription
Free Trial

What do you get with Print?

Product feature icon Instant access to your digital eBook copy whilst your Print order is Shipped
Product feature icon Paperback book shipped to your preferred address
Product feature icon Download this book in EPUB and PDF formats
Product feature icon Access this title in our online reader with advanced features
Product feature icon DRM FREE - Read whenever, wherever and however you want
Table of content icon View table of contents Preview book icon Preview Book

F# High Performance

Chapter 1. Performing Common Optimizations in F#

It's quite well-known today that F# has been a first class citizen, a built-in part of programming language support in Visual Studio, starting from Visual Studio 2010. F# is a programming language that has its own unique trait: it is a functional programming language and at the same time it has object-oriented programming (OOP) support. F# from the start has run on .NET, although we can also run F# on cross-platform, such as Android (using Mono).

Although F# mostly runs faster than C# or VB when doing computations, its own performance characteristics and some not so obvious bad practices and subtleties may have led to performance bottlenecks. The bottlenecks may or may not be faster than the C#/VB counterparts, although some of the bottlenecks may share the same performance characteristics, such as the use of .NET APIs. The main goal of this book is to identify performance problems in F#, measuring and also optimizing F# code to run more efficiently, while also maintaining the functional programming style as appropriately as possible.

Note

A basic knowledge of F# (including the functional programming concept and basic OOP) is required as a prerequisite to start understanding the performance problems and the optimization of F#.

There are many ways to define F# performance characteristics and at the same time to measure them, but understanding the mechanics of running F# code, especially on top of .NET, is crucial and is also a part of the performance characteristics itself. This includes other aspects of approaches to identify concurrency problems and language constructs. This chapter describes the optimization of F# code and will cover the following topics:

  • Understanding the nature of F# code
  • Overview of common bottlenecks
  • Commonly misunderstood concurrency problems
  • Overview of tooling in .NET including Visual Studio to help understanding the running code
  • Immediate testing of F# code in F# interactive
  • Introduction to debugging in F#

Understanding the nature of F# code

Understanding the nature of F# code is very crucial and is a definitive prerequisite before we begin to measure how long it runs and its effectiveness. We can measure a running F# code by running time, but to fully understand why it may run slow or fast, there are some basic concepts we have to consider first.

Before we dive more into this, we must meet the basic requirements and setup.

After the requirements have been set, we need to put in place the environment setting of Visual Studio 2015. We have to set this because we need to maintain the consistency of the default setting of Visual Studio. The setting should be set to General.

These are the steps:

  1. Select the Tools menu from Visual Studio's main menu.
  2. Select Import and Export Settings... and the Import and Export Settings Wizard screen is displayed:

    Understanding the nature of F# code

  3. Select Reset all Settings and then Next to proceed.
  4. Select No, just reset my settings overwriting my current setting and then Next to proceed
  5. Select  General and then click on Finish:

    Understanding the nature of F# code

After setting it up, we will have a consistent layout to be used throughout this book, including the menu locations and the look and feel of Visual Studio.

Now, we are going to scratch the surface of F# runtime with an introductory overview of common F# runtime, which will give us some insights into F# performance.

F# runtime characteristics

The release of Visual Studio 2015 occurred at the same time as the release of .NET 4.6 and the rest of the tools, including the F# compiler. The compiler version of F# in Visual Studio 2015 is F# 4.0.

F# 4.0 has no large differences or notable new features compared to the previous version, F# 3.0 in Visual Studio 2013.

Its runtime characteristic is essentially the same as F# 4.0, although there are some subtle performance improvements and bug fixes.

For more information on what's new in F# 4.0 (described as release notes) visit: 

https://github.com/Microsoft/visualfsharp/blob/fsharp4/CHANGELOG.md

Note

At the time of writing this book, the online and offline MSDN Library of F# in Visual Studio does not have F# 4.0 release notes documentation, but you can always go to the GitHub repository of F# to check the latest update.

These are the common characteristics of F# as part of managed programming language:

  • F# must conform to .NET CLR. This includes the compatibilities, the IL emitted after compilation, and support for .NET BCL (the basic class library). Therefore, F# functions and libraries can be used by other CLR-compliant languages such as C#, VB, and managed C++.
  • The debug symbols (PDB) have the same format and semantics as the other CLR-compliant languages. This is important because F# code must be able to be debugged from other CLR-compliant languages as well.

From the managed languages perspective, measuring the performance of F# is similar when measured by tools such as the CLR profiler. But from an F# unique perspective, the following are the unique characteristics of F#:

  • By default, all types in F# are immutable. Therefore, it's safe to assume it is intrinsically thread safe.
  • F# has a distinctive collection library, and it is immutable by default. It is also safe to assume it is intrinsically thread safe.
  • F# has a strong type inference model, and when a generic type is inferred without any concrete type, it automatically performs generalizations.
  • Default functions in F# are implemented internally by creating an internal class derived from F#'s FSharpFunc. This FSharpFunc is essentially a delegate that is used by F# to apply functional language constructs such as currying and partial application.
  • With tail call recursive optimization in the IL, the F# compiler may emit .tail IL, and then the CLR will recognize this and perform optimization at runtime. More on this in Chapter 7, Language Features and Constructs Optimization.
  • F# has inline functions as options. More on this in Chapter 7, Language Features and Constructs Optimization.
  • F# has a computation workflow that is used to compose functions. This will be described in more detail in Chapter 8, Optimizing Computation Expressions.
  • F# async computation doesn't need Task<T> to implement it.

Note

Although F# async doesn't need the Task<T> object, it can operate well with the async-await model in C# and VB. The async-await model in C# and VB is inspired by F# async, but behaves semantically differently based on more things than just the usage of Task<T>. More on this in Chapter 4, Introduction to Concurrency in F#.

All of those characteristics are not only unique, but they can also have performance implications when used to interoperate with C# and VB.

Relation between F# code and its generated assembly

The F# assembly (commonly known as DLL or executable EXE in .NET running on Windows) is the same as the C#/VB assembly upon compilation. The end product of the compiler is a .NET assembly.

An assembly may contain multiple namespaces, and each namespace may contain multiple files of modules, classes, or a mix of both.

The following table describes the F# relation of code and compiled code (assembly):

F# code

Description

Compiled code

Project

An organization of an F# project. It may contain F# script (FSX) and F# source files (FS).

In the conceptual layout, a project may contain multiple namespaces that spawn across multiple files of FSX and F# script.

An assembly of either executable EXE or DLL class library

Namespace

A logical organization of modules and classes to help organizing within an organization, company, or functionality.

For example: the System.Web namespace that contains many classes related to enable browser/server communication, including HTTP and HTTPS.

A namespace may spawn across different assemblies instead of a namespace for only one assembly

Module

A module in F# is equal to a C# static class or module in VB. An F# FS file may contain multiple modules, although it is not recommended to have this practice.

Part of a generated assembly

Classes and interfaces

A file can contain multiple classes and interfaces under different namespaces. It is recommended to have not more than one namespace for each file as this also minimizes compilation time when it tries to resolve references.

Part of a generated assembly

Immutability versus mutability

F# implementation of types and collection types are immutable. Immutable in this sense means it is read-only, and we can only initialize the object with an initial value and we can't change it afterwards.

Mutability means once we initialize an object, it can be changed afterwards. This is why it is sometimes called a mutating object value instead of a changing object value.

For example consider the following:

let anynumber = 0 

By default, anynumber is immutable and the value of it will always be 0.

To mark a variable as mutable, F# has the mutable keyword and we can use mutable in the let declaration, as in this example:

let mutable anymutablenumber = 0 

However, changing the value requires the use of the <- symbol in F#, for example:

anymutablenumber <- anymutablenumber + 1 

Since the nature of F# is functional, a symbol can be both a data and a function. The content of the symbol is read-only, so does a function in it.

Immutability also has another advantage: it scales well across multiple threads or even in parallel, no matter whether it's a value or a function. The immutability guarantee means that it is free of side effects. It is then safe to spawn multiple symbols in parallel because the result of an execution will be guaranteed to have the same result. This is also simply called thread safe.

The fact that F# has a mixed support for functional and OOP at the same time (including having support for the inherent mutable state of OOP) may lead to bottlenecks as described next.

Overview of common bottlenecks

F# has common bottlenecks although they might be subtle as well.

In order to be able to quickly understand the bottleneck factors in F#, we will categorize the shared general bottlenecks of .NET as managed bottlenecks (also in C#/VB), and F#-only bottlenecks (this includes when using F# with other languages).

The following are managed .NET bottlenecks (from obvious to less obvious):

  • String concatenations, such as using string String.Concat instead of StringBuilder. This is often overlooked because of a lack of awareness of the string's immutability.
  • Usage of non-generic collections such as ArrayList.
  • Incorrectly handling side effects, such as exceptions and I/O.
  • Mutable objects usage, including casting.
  • Complex objects that will be serialized and deserialized, for example: sending DataSet that has DataTables over HTTP.
  • Ignoring performance profiling.

Side effects mean all of the elements outside the formal computation (it is often called the outside world) that we interact with, and this includes the changing global state. The outside world can be all of the things that we cannot fully determine as the end result. Examples of the outside world include:

  • I/O: This is included as being part of the outside world because you cannot determine or guarantee any kind of work you pass to I/O to be successfully completed. For example, when sending a command to a printer to print a document, we cannot guarantee 100% success of the printing operation. We cannot even guarantee that the process of sending the data to the printer will be successful or not before the printer receives the data and begins to print the document.
  • Global static mutable variables: A quick example of this is when we define a public static variable in the scope of ASP.NET. Every value change will always change the condition of any user of the ASP.NET application.
  • Functions or properties that always have different results when they are invoked, such as DateTime.Now.

Note

DateTime.Now will always return different results and this is as expected because the result must change every time it is called or instantiated. It is not free of side effects, but it is still expected to always return a different result.

Side effects are not just for functional programming developers, as many of us are now becoming quite aware. There are no absolute side effect-free computations because we should learn and be able to correctly handle them. For example, even printing a screen to a console is also a side effect because it involves I/O, and it changes the state of the outside world.

The following are F#'s unique bottlenecks:

  • Incorrect use of data structures and collections
  • Incorrect use of auto generalization and other language constructs
  • Incorrectly implemented concurrency problems, such as mixing synchronous and asynchronous although the original intention is asynchronous
  • Slow performance when having to interoperate with other languages' class libraries such as C#/VB
  • Scaling MailboxProcessor in F#
  • Identifying when tail call optimization should occur
  • Slow response when resolving type in type provider implementation
  • Slow performance when implementing computation workflow

Common samples of misunderstood concurrent problems

Many of us, when dealing with concurrent problems, sometimes try to use a hammer for every nail. There is no silver bullet for all of the problems of implementing concurrency.

It is also recommended to understand concurrency, as concurrency is now becoming more relevant because of the many core models in the releases of modern microprocessors (or simply processors) in the last 7 years. This fact is also becoming a trend as the clock speed of the latest processors has been usually limited to 3.2 GHz for the last 3 years.

Microsoft's Visual C++ architect, Herb Sutter, has written a very thorough article in the form of a whitepaper famously known as The Free Lunch Is Over

http://www.gotw.ca/publications/concurrency-ddj.htm

Let's understand first what concurrency is and the F# supports.

Introduction to concurrency in F#

Before we dive deeper into concurrency in F#, we should understand the definition of concurrency.

Concurrency is one of the main disciplines of computer science and it is still one of the main problems of computations.

Simply defined, concurrency is the composition of the order of independent process units or partially-ordered process units that can be executed in parallel or not in parallel, but not in sequential order. The term order in this context means ordered as sequentially.

The following diagram illustrates the concept of sequential (not concurrent) in action:

Introduction to concurrency in F#

Process 1 to Process 4 as shown in the preceding diagram is executed sequentially step by step. Process 2 must wait for Process 1 to be completed first, as do Process 3 and Process 4.

This sequence is also called a synchronous process or is simply referred to as being synchronous.

The following figure is a sample illustration of a parallel concurrency combination of parallel and synchronous processes:

Introduction to concurrency in F#

Processes  1A, 2A, and 3A run in parallel, although each parallel lane has its own sequence of processes that are run sequentially.

The term parallel means that it is not just executing simultaneously in parallel, but parallel also means that it may run on many processors or on many cores, as is common in modern processors that have multiple cores.

Defining asynchronous

A simple definition of asynchronous means not synchronous. This means that if we have an asynchronous flow, the process is not run synchronously.

These are the implications of an asynchronous flow:

  • Processes run not sequentially. For example, if the first process is running asynchronously, the next process doesn't have to wait for the first process to be completed.
  • There has to be a way of scheduling and telling the scheduler to inform that the asynchronous process is completed. Typically, the asynchronous process is usually related to blocking I/O or some long computations.
  • At first, the processes may look sequential, but the next process run may not be sequential at all.

This is a sample case of asynchronous: a customer is going to have dinner in a restaurant. The flows are:

  1. Customer A orders some food or drinks, and the order is noted by waiter X. Usually, most restaurants have more than one waiter, but for this illustration, the waiter available currently to serve customer A is waiter X.
  2. Waiter X then gives the list of the customer's order to chef Y.
  3. Chef Y accepts the order, and checks if he is currently occupied or not. If he is occupied, the order is registered as part of his cooking queue. Otherwise, he will start to cook the order.
  4. The waiter does not have to wait for the chef to complete his cooking. He can then serve other customers who have just arrived or there might be customers that want to add more food or drinks as well.
  5. Chef Y finishes his cooking for customer A, and then gives a notification to waiter X to inform that his cooking for customer A is finished. Or he can inform all waiters to tell that the cooking for customer A is finished. This concept of informing to tell a process is finished is commonly called a callback.
  6. Waiter X (or any other waiter) delivers the finished food to customer A.

The asynchronous model that uses a notification to inform that a process is completed is called asynchronous callback.

The result returned at the end of the execution later (or in the future) is called a Future. It is also the future, in a sense, when many processes are executed in parallel, having results later.

This is the official documentation of Future in MSDN Library: 

https://msdn.microsoft.com/en-us/library/ff963556.aspx

For I/O operations, such as printing a document, we cannot determine whether the printing is successful or not, so the notification of the end process is not available. We can implement an asynchronous operation on I/O, and the fact that there is no observable notification of this is why this asynchronous model is called the asynchronous fire and forget model.

Misunderstood concurrency problems

Many developers, even seasoned or experienced developers, still think that concurrency and parallel programming are different. Actually, parallel programming is just one member within the concurrency discipline, together with the differentiation of asynchronous and synchronous processing models.

This is also one of the most misunderstood concurrency concepts or problems, and there are many more regarding how we approach concurrency.

These are some common organized sample cases of misunderstood concurrency problems:

  1. Assuming all concurrent problems can be solved using parallel programming.

    Fact: Not all concurrent problems are easily solved with parallelism.

  2. Assuming all implementation of asynchronous is asynchronous.

    Fact: This depends on how we implement async; sometimes the execution of an async construct is executed synchronously.

  3. Ignoring blocking threads such as I/O.

    Fact: Blocking I/O threads should be handled asynchronously; otherwise, the current thread is always waiting indefinitely until the I/O thread is finished.

  4. The synchronized lock is blocking.

    Fact: The lock is not a blocking thread.

  5. Relying on the CPU speed.

    Fact: The CPU speed increase is becoming less of an issue. The research and development of modern CPUs is focusing on multiple core CPUs.

A few sample cases of concurrent problems are mentioned as follows:

The case samples of the first case are:

  • Ordering or sorting a collection: Ordering is by default a sequential process, and it requires iterating all the elements of the collection. Therefore, it's useless to use parallelism.
  • Grouping data: Grouping data is implicitly one of the sequential processes; it is also quite useless to use parallelism.
  • Printing reports: Printing is part of I/O and I/O is intrinsically without support for parallelism. Unless the I/O is part of I/O parallelism, it is useless to use parallelism in this context.

Sample cases of the second case are listed as follows:

  • Mixing Parallel.For that has F# async in it. The implications of having Parallel.For is by default taking a multiple core or a CPU to run it is not the same as running asynchronously, as it is not guaranteed to run as a combined async in parallel.
  • Using Thread.Sleep instead of Async.Sleep to signify a wait operation. The call to Thread.Sleep will instead make the flow synchronous, as the Sleep method simply puts on hold the current thread as a delay synchronously.

Note

RAID array in the storage I/O is one of the best samples of parallelism in I/O. It stores data in parallel across multiple disks. It is faster than common I/O because data is stored in parts (not whole data to a disk) to several disks in parallel.

The third case is related to all of the I/O operations including sending data to a printer and saving large data into a disk. These operations are always blocking threads.

For the case of lock, Microsoft has issued official statements that lock in .NET used by C# and VB is executed without any interruption, and it only locks an object until it has finished executing the block in the synchronized lock. It's still allowing other threads to run without waiting for the thread that has the lock to finish.

This is the official thread synchronization of C# and VB in MSDN: 

https://msdn.microsoft.com/en-us/library/ms173179.aspx

It is recommended to always check online the MSDN Library of the .NET class library, as this is always updated.

Introduction to concurrency support in .NET and F#

Concurrency support in F# is based on the existing work of concurrency support features in .NET BCL (the Base Class Library). It's also by design, since F# runs on top of .NET CLR and can use .NET BCL. F# also has its unique ways that bring more features other than just language features (for example, asynchronous computations).

The .NET BCL part of concurrency has basic support for the following:

  • Thread
  • Lock
  • Mutex

Beginning with .NET 4.0, we have the Task Parallel Library (TPL). This library makes concurrent support easier. TPL consists of the following:

  • Data parallelism (for example: Parallel.For and ForEach)
  • Task parallelism
  • Asynchronous task (this is also the base foundation of C#/VB's async-await)
  • Parallel LINQ (often abbreviated as PLINQ)

For a more complete reference of concurrency support in .NET, please visit https://msdn.microsoft.com/en-us/library/hh156548(v=vs.110).aspx.

Note

.NET has no support yet for fiber API in Win32 API. Microsoft currently has no definite plan for fiber support.

F# has its own unique features of concurrency supports. They are:

  • Asynchronous workflow or computation
  • MailboxProcessor
  • Parallel async
  • Parallel async combined with I/O

More on concurrency support in F# is available in Chapter 4, Introduction to Concurrency in F# and Chapter 5, Advanced Concurrency Support in F#.

Now it's time to dive more into some codes. To start writing F# code, we can use F# and Visual Studio combined. This includes IDE supports for F#.

Overview of F# tooling in Visual Studio

F# has been supported in Visual Studio since Visual Studio 2010, and in Visual Studio 2015 the support has improved with better syntax colorizations than Visual Studio 2010, not just IDE. This F# IDE support is officially called Visual F#.

This tooling is available as open source from Microsoft and it is available to be downloaded from GitHub at https://github.com/Microsoft/visualfsharp/.

And the F# compiler itself is open source and it is also available from GitHub (including the design proposal discussions) at https://github.com/fsharp.

The tooling is under the governance of Microsoft, but it is welcoming community contributions as it is available on GitHub. All of the community participations of tooling, compilers and the language specifications are under the governance of the F# Software Foundation (FSSF).

We can also support FSSF directly. For more information about FSSF, please visit http://fsharp.org/.

Note

The F# community projects are also managed by FSSF, and it is welcoming contributions as well. FSSF is an independent entity and it is not tied to Microsoft.

Visual F# in Visual Studio 2015 has mainly the following capabilities:

  • Project template support, including the NuGet package addition and references to other projects in the same solution file. The other projects can be VB or C# projects, not just F#.
  • AssemblyInfo support in a separate file. This feature has been available since Visual Studio 2015. Previously it was only available in C# and VB projects.
  • The F# compiler, FSC, is used to compile F# into .NET executable and libraries in the form of DLL.
  • Integration of the F# compiler, MSBuild infrastructure, and also Intellisense.
  • F# libraries, a foundation to the functional programming constructs of F# and F# unique concurrency features such as asynchronous workflow and MailboxProcessor. It also contains many useful functions to further interoperate with C#/VB, including interoperating with .NET delegates.
  • Interactive support for the F# interactive (FSI) prompt in the IDE.

For more information about F# tooling, this is the official MSDN Library link: 

https://msdn.microsoft.com/visualfsharpdocs/conceptual/visual-fsharp

It is recommended to always consult the Visual F# documentation on GitHub first, then combine it with the online MSDN Library section of F#.

Microsoft has planned to rebuild all of the online MSDN Library to use the GitHub participation model, so developers can submit a pull request to modify or to amend any documentation page. Visual F# is now being reworked on as well, but there are some pages still left behind inside Visual F# GitHub repo.

To always check the latest development of F# documentation on GitHub, visit https://github.com/Microsoft/visualfsharpdocs.

Interactive support for F# interactive

F# interactive is a tool to interpret your F# code and run it immediately. It will also process and show the results, the types, and the syntax errors. The code can be run in the interactive prompt or taken from the source code and then run into F# interactive.

Note

The concept of having interpreted code, executing it, and seeing the results is called REPL. REPL is abbreviated from Read-Eval-Print-Loop, and it was first available as the system's command-line prompt. There is nothing new about this REPL concept, as other programming languages such as Python already have had REPL before F#.

Compared to C# and VB, F# interactive is the first to have interactive REPL support since Visual Studio 2010. Unfortunately, there is no Visual Studio's Intellisense support for F# interactive yet.

There are two ways to use F# interactive:

  • In Visual Studio IDE
  • In Command Prompt

The most common usage of F# interactive is within Visual Studio IDE.

We have to set up the F# Interactive window to be displayed in order to use F# interactive.

These are the steps to display the F# Interactive window:

  1. Open the View menu from the Visual Studio main menu.
  2. Choose Other Windows.. and then choose F# Interactive.

A window that hosts the F# Interactive within Visual Studio will appear and it will be ready to interpret our F# code:

Interactive support for F# interactive

As a starter, type #help followed by ;; to mark as closing statements to be evaluated. We now see some further options:

Interactive support for F# interactive

F# interactive can be used to not only interpret and run F# code but also as a way to see immediate results of a calculation.

Type 5 * 25;; and press Enter.

We now see the result of that calculation:

Interactive support for F# interactive

We can also execute codes in the Visual Studio editor when we are opening F# source code file.

For example, create a new project using the F# tutorial project template:

Interactive support for F# interactive

You may find that your display of Visual Studio is different from the previous screenshot. Actually, the aforementioned display depends on what Visual Studio edition we have. For Visual Studio Enterprise, more templates are available for us to use, such as the Modeling Projects to create UML.

For the purpose of F#, the project templates of the F# projects are the same for the Community Edition and above.

After creating the project, an F# project contains Tutorial.fsx.

Before we use F# interactive, we should turn on the option for displaying line numbers. It is also recommended to have this option always turned on, as it will provide easier navigation to the code we write:

  1. Go to the Tools menu and choose Options. It is available in F# options in the Options dialog:

    Interactive support for F# interactive

  2. Now double-click Tutorial.fsx, and highlight lines 44 to 61:

    Interactive support for F# interactive

  3. Then press Alt + Enter. F# interprets the code. We can see the result of the interpretation in F# Interactive:

    Interactive support for F# interactive

We have tried F# interactive from within the Visual Studio IDE. Let's use F# interactive from Command Prompt.

Note

We can also use Ctrl + Alt + F to activate or open F# Interactive.

To use F# interactive from Command Prompt, we call the executable FSI directly from Command Prompt.

The best way to run FSI is from Visual Studio's developer Command Prompt. This developer Command Prompt is available under the Visual Studio 2015 folder on the start menu of the Windows desktop menu bar.

Select it, and now we have the Developer Command Prompt for VS2015:

Interactive support for F# interactive

Type FSI and press Enter.

We can try to write some code to evaluate, such as:

let anynumber = 5 * 25;; 

Press Enter. The immediate result will be displayed:

Interactive support for F# interactive

To quit the FSI, type #quit;; and press Enter.

Using F# interactive from Command Prompt is faster but it is also not quite so user-friendly because we cannot evaluate multiple lines of code easily. It is easier to evaluate this in Visual Studio IDE.

Note

For simplicity and ease of use, the rest of this book will always use FSI within the Visual Studio IDE.

For more information about F# FSI, consult the FSI reference from the MSDN Library at  https://msdn.microsoft.com/visualfsharpdocs/conceptual/fsharp-interactive-%5bfsi.exe%5d-reference.

FSI is also configurable. We can configure FSI further by leveraging the FSI class library in the Microsoft.FSharp.Compiler.Interactive namespace. More information on this library is also available at the F# FSI URL mentioned previously.

Introduction to debugging in F#

There is one aspect of understanding running F# code that is crucial: debugging F# code. We have to be able to debug F# code, especially when we have very large projects that have hundreds of F# code files, not to mention when each of the code files may have too many lines of code. For example, having to check a running F# code that has more than 2,000 lines.

The following are the advantages of the debug features:

  • Isolating the error and focusing on it by inserting a breakpoint can ease the fixing of an error or bug. Developers are gaining more productivity because they can fix errors/bugs faster.
  • Debugging can also provide insightful information about the correctness of any value returning from a function.
  • Debugging can also be used to trace bugs further by examining the results from other referenced libraries as well. It is possible that we may use the referenced library incorrectly or the referenced library may also have bugs.

Visual F# in Visual Studio 2015 also has debugging capabilities. It was not as powerful when it was introduced in Visual Studio 2008 as additional add-on, but now the debugging experience is much better. It has been integrated with the Visual Studio extensibility model nicely, providing, for example, faster execution while running in the debug mode and having conditional breakpoints.

It is different from the C#/VB debugger because F#, although being a strongly and strictly typed language, currently has no support for evaluating expressions in the debugger's immediate windows in Visual Studio 2015.

Note

Some experienced F# developers may argue that this additional debug feature is not a big concern at all as F# has a tendency to enforce type restriction and correctness at the fabric of F# as a programming language. But for most other developers, especially those who jump from C#/VB to F#, the overall debugging experience is still lacking some features.

Currently these are the differences between the F# and C#/VB debugger in Visual Studio 2015:

Feature

F#

C#/VB

Breakpoint insertion

Yes.

Yes

Condition in breakpoint

Yes.

Yes

Intellisense in editing condition in breakpoint

Not supported because Intellisense is not yet linked to the whole infrastructure of the Visual Studio 2015 IDE extensibility and the F# compiler. There is a plan to have this feature for the next Visual Studio release after Visual Studio 2015.

Yes

Lightbulb assistant

Not available. There is a plan to have this feature for the next Visual Studio release after Visual Studio 2015, but the exact planned release is not quite clear.

Yes

Expression evaluation in immediate window

Not available.

Yes

Locals value

Yes.

Yes

Auto watch value

Yes.

Yes

Other than the features in the previous table, basic debugging with breakpoints in Visual F# is essentially the same as debugging in C#/VB.

Let's take some code to debug. To quickly have some code, we can use the F# 3.0 sample from CodePlex at:

http://fsharp3sample.codeplex.com/

After downloading the ZIP file of the code samples, unzip it to a folder and open the SampleProject.sln solution file in Visual Studio.

Note

You may read Readme.txt first before using the whole sample code. This readme guide is available in the Solution Item folder when opened in Solution Explorer.

Now, your screen should look like this:

Introduction to debugging in F#

Some of the samples in F# 3.0 are not valid anymore. You have to register for Azure DataMarket to access the F# Type Provider of Azure DataMarket.

There are some compiler errors if we try to rebuild the solution without changing the code at all, and one of the sample type providers, ESRI DataMarket, is not working.

Based on those invalid type provider conditions, to build this sample solution successfully, you have to follow these steps:

  1. Register with Azure DataMarket. You need to have your own Azure account key to access Azure DataMarket.
  2. The ESRI sample has not been working since 2014. Please comment the lines from line 135 to line 157 in the Samples.TypeProviders.AzureMarketPlace.fs file.
  3. Rebuild the solution. This will compile the whole solution and also resolve the type provider in the background for us to use.
  4. Now open the Samples.Beginners.fs file. Put the debugger breakpoints at lines 19 and 20 by clicking the line.
  5. To add breakpoints, you can simply toggle the highlighted column on the left before the line number like this:

    Introduction to debugging in F#

  6. And we can also add breakpoints by right clicking and choosing Breakpoints.. and then Insert Breakpoint.
  7. Compile the code by initiating the Build Solution. Then press F5 to run. The window of F# Micro Sample Explore is displayed:

    Introduction to debugging in F#

    This sample is actually a showcase of many F# features, from basic language constructs, units of measure, type providers, and LINQ, to concurrency such as async and parallelism.

  8. Now expand the Basic node on the left and choose Basic Data Types, and then choose the last node of Integer Arithmetic, as illustrated here:

    Introduction to debugging in F#

  9. Going back to the source code of Samples.Beginner.fs, we can see that the node name is also the same as the name of the attributes in the code to categorize:
          [<Category("Basic Data Types"); 
            Title("Integer Arithmetic"); 
            Description("This sample shows some basic integer arithmetic")>] 
          let SampleArithmetic1() = 
              let x = 10 + 12 - 3  
              let y = x * 2 + 1  
              let r1,r2 = x/3, x%3 
              printfn "x = %d, y = %d, r1 = %d, r2 = %d" x y r1 r2 
    
  10. Click the Run Sample! button and Visual Studio will stop the execution at the breakpoint:

    Introduction to debugging in F#

    Now we can debug our code easily. We can also look at the value of the variables or symbols that are currently in scope by checking the value at the Locals window.

  11. Press F10 to step over, and now we see the evaluated value of x and y:

    Introduction to debugging in F#

Any local variables in Locals and watch expressions displayed in the Watch1 window always have the name, value, and type of the variables. The type displayed is using the F# keyword, not the full type name.

For example, int is displayed instead of System.Int32 as shown in Locals.

We can always check other values as well if we have another global or static global variable in the Watch1 window. The values can contain immediate values from an expression, for example DateTime.Now.

Unfortunately, we have to write using the full namespace of System.DateTime, so we have to write the expression as System.DateTime.Now:

Introduction to debugging in F#

This requirement to have the full namespace proves that debugger support in Visual F# still requires improvements compared to its C#/VB counterparts. Typing the full object name may be error prone, as F# watch does not support Intellisense yet.

After we have finished debugging and bug fixing, it is recommended to change the compilation to the Release mode. The Release mode will have a smaller compiled F# code and it executes faster because it does not contain debug symbols and any other debug information attached to the compiled code.

To change back and forth between Debug and Release is quite easy. We can simply change the mode at the drop-down menu in the Visual Studio toolbar:

Introduction to debugging in F#

There is no apparent distinction on the compiled DLL or EXE filename, other than the smaller size of the release mode.

To summarize, the following are the differences of the Debug mode and the Release mode:

Elements

Debug

Release

Debug symbol (PDB)

Included

Not included.

Size of compiled code

Bigger than the release mode, excluding the PDB file

Smaller than the debug mode.

Code optimization

Not optimized, as it is focused for debugging and it is also synchronized

Yes, but the code will not be able to be debugged easily, as the code is optimized for executions.

In .NET 4.6 and Windows 10, it is optimized further by compiling into native code using the Ahead Of Time (AOT) model instead of Just In Time (JIT).

Compilation symbol availability

DEBUG

Not applicable.

Execution

Slower than Release, as there is no optimization

Fast, since it is optimized for runtime, and there is no debug symbol overhead.

For more information about AOT and JIT, consult the MSDN Library at https://msdn.microsoft.com/en-us/library/dn807190(v=vs.110).aspx.

Summary

We discussed the introduction to performing common performance optimizations, from the performance characteristics of F# and .NET to the most commonly used optimization concepts such as concurrency. We also have a basic knowledge to start troubleshooting performance problems by debugging using Visual Studio. But debugging running F# code is still a small part of performance optimization because debugging only provides an insight of the values and the states of objects in our code.

The debug support of F# tooling itself is not enough to fully understand the details of performance problems because most of the detailed performance optimization requires us to measure the benchmark of our code. The measurement of performance in order to objectively measure optimization will be described in Chapter 2Performance Measurement.

Left arrow icon Right arrow icon

Key benefits

  • Explore the advanced concurrency support in F# and .NET TPL
  • Covers major optimization techniques in F# to improve the performance of applications
  • Use Struct, Class and Record model, Interop with C# and VB without sacrificing performance.

Description

F# is a functional programming language and is used in enterprise applications that demand high performance. It has its own unique trait: it is a functional programming language and has OOP support at the same time. This book will help you make F# applications run faster with examples you can easily break down and take into your own work. You will be able to assess the performance of the program and identify bottlenecks. Beginning with a gentle overview of concurrency features in F#, you will get to know the advanced topics of concurrency optimizations in F#, such as F# message passing agent of MailboxProcessor and further interoperation with .NET TPL. Based on this knowledge, you will be able to enhance the performance optimizations when implementing and using other F# language features. The book also covers optimization techniques by using F# best practices and F# libraries. You will learn how the concepts of concurrency and parallel programming will help in improving the performance. With this, you would be able to take advantage of multi-core processors and track memory leaks, root causes, and CPU issues. Finally, you will be able to test their applications to achieve scalability.

Who is this book for?

This book is for F# developers who want to build high-performance applications. Knowledge of functional programming would be helpful.

What you will learn

  • Understand how the execution of functions in F# works
  • Identify common performance bottlenecks
  • Implement best practices to optimize performance
  • Use the available tooling to help measure performance
  • Combine the best practice of asynchronous and synchronous
  • Optimize further using various F# language constructs
Estimated delivery fee Deliver to New Zealand

Standard delivery 10 - 13 business days

NZ$20.95

Premium delivery 5 - 8 business days

NZ$74.95
(Includes tracking information)

Product Details

Country selected
Publication date, Length, Edition, Language, ISBN-13
Publication date : Jan 18, 2017
Length: 338 pages
Edition : 1st
Language : English
ISBN-13 : 9781786468079
Vendor :
Microsoft
Category :
Languages :

What do you get with Print?

Product feature icon Instant access to your digital eBook copy whilst your Print order is Shipped
Product feature icon Paperback book shipped to your preferred address
Product feature icon Download this book in EPUB and PDF formats
Product feature icon Access this title in our online reader with advanced features
Product feature icon DRM FREE - Read whenever, wherever and however you want
Estimated delivery fee Deliver to New Zealand

Standard delivery 10 - 13 business days

NZ$20.95

Premium delivery 5 - 8 business days

NZ$74.95
(Includes tracking information)

Product Details

Publication date : Jan 18, 2017
Length: 338 pages
Edition : 1st
Language : English
ISBN-13 : 9781786468079
Vendor :
Microsoft
Category :
Languages :

Packt Subscriptions

See our plans and pricing
Modal Close icon
$19.99 billed monthly
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Simple pricing, no contract
$199.99 billed annually
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Choose a DRM-free eBook or Video every month to keep
Feature tick icon PLUS own as many other DRM-free eBooks or Videos as you like for just NZ$7 each
Feature tick icon Exclusive print discounts
$279.99 billed in 18 months
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Choose a DRM-free eBook or Video every month to keep
Feature tick icon PLUS own as many other DRM-free eBooks or Videos as you like for just NZ$7 each
Feature tick icon Exclusive print discounts

Frequently bought together


Stars icon
Total NZ$ 215.97
Mastering F#
NZ$71.99
F# 4.0 Design Patterns
NZ$71.99
F# High Performance
NZ$71.99
Total NZ$ 215.97 Stars icon

Table of Contents

8 Chapters
1. Performing Common Optimizations in F# Chevron down icon Chevron up icon
2. Performance Measurement Chevron down icon Chevron up icon
3. Optimizing Data Structures Chevron down icon Chevron up icon
4. Introduction to Concurrency in F# Chevron down icon Chevron up icon
5. Advanced Concurrency Support in F# Chevron down icon Chevron up icon
6. Optimizing Type Provider Chevron down icon Chevron up icon
7. Language Features and Constructs Optimization Chevron down icon Chevron up icon
8. Optimizing Computation Expressions Chevron down icon Chevron up icon

Customer reviews

Rating distribution
Full star icon Full star icon Full star icon Full star icon Full star icon 5
(1 Ratings)
5 star 100%
4 star 0%
3 star 0%
2 star 0%
1 star 0%
Musa Mar 12, 2021
Full star icon Full star icon Full star icon Full star icon Full star icon 5
Steps into Assembly language exposure to abstract functional language F#. Steps up to illustrate by building Message Queues, Computation Expressions, Type Providers,, with examples. CE example builds WPF window with panel & buttons etc from within F# syntax . F# pronounced F Sharp has a shorter cleaner syntax to other functional languages such as Haskel, Scala, functional-Java or Python today ~ an order shorter & faster approx. This may be 1 of 5 better books on f# others may be by Scott Wlaschin,... other are terse but tackled Hilbert curves, hardware BDD topics as Hansen-Rischel, Don Syme,
Amazon Verified review Amazon
Get free access to Packt library with over 7500+ books and video courses for 7 days!
Start Free Trial

FAQs

What is the delivery time and cost of print book? Chevron down icon Chevron up icon

Shipping Details

USA:

'

Economy: Delivery to most addresses in the US within 10-15 business days

Premium: Trackable Delivery to most addresses in the US within 3-8 business days

UK:

Economy: Delivery to most addresses in the U.K. within 7-9 business days.
Shipments are not trackable

Premium: Trackable delivery to most addresses in the U.K. within 3-4 business days!
Add one extra business day for deliveries to Northern Ireland and Scottish Highlands and islands

EU:

Premium: Trackable delivery to most EU destinations within 4-9 business days.

Australia:

Economy: Can deliver to P. O. Boxes and private residences.
Trackable service with delivery to addresses in Australia only.
Delivery time ranges from 7-9 business days for VIC and 8-10 business days for Interstate metro
Delivery time is up to 15 business days for remote areas of WA, NT & QLD.

Premium: Delivery to addresses in Australia only
Trackable delivery to most P. O. Boxes and private residences in Australia within 4-5 days based on the distance to a destination following dispatch.

India:

Premium: Delivery to most Indian addresses within 5-6 business days

Rest of the World:

Premium: Countries in the American continent: Trackable delivery to most countries within 4-7 business days

Asia:

Premium: Delivery to most Asian addresses within 5-9 business days

Disclaimer:
All orders received before 5 PM U.K time would start printing from the next business day. So the estimated delivery times start from the next day as well. Orders received after 5 PM U.K time (in our internal systems) on a business day or anytime on the weekend will begin printing the second to next business day. For example, an order placed at 11 AM today will begin printing tomorrow, whereas an order placed at 9 PM tonight will begin printing the day after tomorrow.


Unfortunately, due to several restrictions, we are unable to ship to the following countries:

  1. Afghanistan
  2. American Samoa
  3. Belarus
  4. Brunei Darussalam
  5. Central African Republic
  6. The Democratic Republic of Congo
  7. Eritrea
  8. Guinea-bissau
  9. Iran
  10. Lebanon
  11. Libiya Arab Jamahriya
  12. Somalia
  13. Sudan
  14. Russian Federation
  15. Syrian Arab Republic
  16. Ukraine
  17. Venezuela
What is custom duty/charge? Chevron down icon Chevron up icon

Customs duty are charges levied on goods when they cross international borders. It is a tax that is imposed on imported goods. These duties are charged by special authorities and bodies created by local governments and are meant to protect local industries, economies, and businesses.

Do I have to pay customs charges for the print book order? Chevron down icon Chevron up icon

The orders shipped to the countries that are listed under EU27 will not bear custom charges. They are paid by Packt as part of the order.

List of EU27 countries: www.gov.uk/eu-eea:

A custom duty or localized taxes may be applicable on the shipment and would be charged by the recipient country outside of the EU27 which should be paid by the customer and these duties are not included in the shipping charges been charged on the order.

How do I know my custom duty charges? Chevron down icon Chevron up icon

The amount of duty payable varies greatly depending on the imported goods, the country of origin and several other factors like the total invoice amount or dimensions like weight, and other such criteria applicable in your country.

For example:

  • If you live in Mexico, and the declared value of your ordered items is over $ 50, for you to receive a package, you will have to pay additional import tax of 19% which will be $ 9.50 to the courier service.
  • Whereas if you live in Turkey, and the declared value of your ordered items is over € 22, for you to receive a package, you will have to pay additional import tax of 18% which will be € 3.96 to the courier service.
How can I cancel my order? Chevron down icon Chevron up icon

Cancellation Policy for Published Printed Books:

You can cancel any order within 1 hour of placing the order. Simply contact customercare@packt.com with your order details or payment transaction id. If your order has already started the shipment process, we will do our best to stop it. However, if it is already on the way to you then when you receive it, you can contact us at customercare@packt.com using the returns and refund process.

Please understand that Packt Publishing cannot provide refunds or cancel any order except for the cases described in our Return Policy (i.e. Packt Publishing agrees to replace your printed book because it arrives damaged or material defect in book), Packt Publishing will not accept returns.

What is your returns and refunds policy? Chevron down icon Chevron up icon

Return Policy:

We want you to be happy with your purchase from Packtpub.com. We will not hassle you with returning print books to us. If the print book you receive from us is incorrect, damaged, doesn't work or is unacceptably late, please contact Customer Relations Team on customercare@packt.com with the order number and issue details as explained below:

  1. If you ordered (eBook, Video or Print Book) incorrectly or accidentally, please contact Customer Relations Team on customercare@packt.com within one hour of placing the order and we will replace/refund you the item cost.
  2. Sadly, if your eBook or Video file is faulty or a fault occurs during the eBook or Video being made available to you, i.e. during download then you should contact Customer Relations Team within 14 days of purchase on customercare@packt.com who will be able to resolve this issue for you.
  3. You will have a choice of replacement or refund of the problem items.(damaged, defective or incorrect)
  4. Once Customer Care Team confirms that you will be refunded, you should receive the refund within 10 to 12 working days.
  5. If you are only requesting a refund of one book from a multiple order, then we will refund you the appropriate single item.
  6. Where the items were shipped under a free shipping offer, there will be no shipping costs to refund.

On the off chance your printed book arrives damaged, with book material defect, contact our Customer Relation Team on customercare@packt.com within 14 days of receipt of the book with appropriate evidence of damage and we will work with you to secure a replacement copy, if necessary. Please note that each printed book you order from us is individually made by Packt's professional book-printing partner which is on a print-on-demand basis.

What tax is charged? Chevron down icon Chevron up icon

Currently, no tax is charged on the purchase of any print book (subject to change based on the laws and regulations). A localized VAT fee is charged only to our European and UK customers on eBooks, Video and subscriptions that they buy. GST is charged to Indian customers for eBooks and video purchases.

What payment methods can I use? Chevron down icon Chevron up icon

You can pay with the following card types:

  1. Visa Debit
  2. Visa Credit
  3. MasterCard
  4. PayPal
What is the delivery time and cost of print books? Chevron down icon Chevron up icon

Shipping Details

USA:

'

Economy: Delivery to most addresses in the US within 10-15 business days

Premium: Trackable Delivery to most addresses in the US within 3-8 business days

UK:

Economy: Delivery to most addresses in the U.K. within 7-9 business days.
Shipments are not trackable

Premium: Trackable delivery to most addresses in the U.K. within 3-4 business days!
Add one extra business day for deliveries to Northern Ireland and Scottish Highlands and islands

EU:

Premium: Trackable delivery to most EU destinations within 4-9 business days.

Australia:

Economy: Can deliver to P. O. Boxes and private residences.
Trackable service with delivery to addresses in Australia only.
Delivery time ranges from 7-9 business days for VIC and 8-10 business days for Interstate metro
Delivery time is up to 15 business days for remote areas of WA, NT & QLD.

Premium: Delivery to addresses in Australia only
Trackable delivery to most P. O. Boxes and private residences in Australia within 4-5 days based on the distance to a destination following dispatch.

India:

Premium: Delivery to most Indian addresses within 5-6 business days

Rest of the World:

Premium: Countries in the American continent: Trackable delivery to most countries within 4-7 business days

Asia:

Premium: Delivery to most Asian addresses within 5-9 business days

Disclaimer:
All orders received before 5 PM U.K time would start printing from the next business day. So the estimated delivery times start from the next day as well. Orders received after 5 PM U.K time (in our internal systems) on a business day or anytime on the weekend will begin printing the second to next business day. For example, an order placed at 11 AM today will begin printing tomorrow, whereas an order placed at 9 PM tonight will begin printing the day after tomorrow.


Unfortunately, due to several restrictions, we are unable to ship to the following countries:

  1. Afghanistan
  2. American Samoa
  3. Belarus
  4. Brunei Darussalam
  5. Central African Republic
  6. The Democratic Republic of Congo
  7. Eritrea
  8. Guinea-bissau
  9. Iran
  10. Lebanon
  11. Libiya Arab Jamahriya
  12. Somalia
  13. Sudan
  14. Russian Federation
  15. Syrian Arab Republic
  16. Ukraine
  17. Venezuela