Erlang

By Martin Heller

In my December, 2002 column, I discussed the Lightweight Languages conference I attended at MIT in November. One of the languages presented there was Erlang, named after Agner Krarup Erlang (1878-1929), a Danish mathematician who developed a theory of stochastic processes in statistical equilibrium that is widely used in the telecommunications industry.

Joe Armstrong of the Distributed Systems Laboratory of the Swedish Institute of Computer Science gave the talk. Joe was and is one of the architects of the language and one of the authors of Concurrent Programming in Erlang (Prentice Hall), along with Robert Virding, Claes Wikström, and Mike Williams.

A Little History

Erlang was designed for programming concurrent, real-time, distributed fault-tolerant systems. Erlang was designed in parallel with its first applications, in an internal project about languages for switching systems at Ericsson, the Swedish telecom giant. At first, Erlang was a secret project. Initially, it was slow, as the implementation was done on top of a Prolog interpreter; later, it was reimplemented with a compiler, on several operating systems and processors, and met its designers' performance goals.

Meanwhile, Ericsson, in its infinite wisdom, standardized on C++ for all its new projects, which led to Erlang becoming an open source language. One consequence was that the Erlang team left Ericsson for a startup. Another consequence of this is that one of Ericsson's biggest competitors, Nortel Networks, adopted Erlang for some of its own products, including the Alteon SSL Accelerator.

Meanwhile, back at Ericsson, some Erlang-based products that were already in progress when the "ban" went into effect came to market, including the AXD 301, an ATM switch with 99.9999999 percent reliability (9 nines, or 31 ms. downtime a year!), which has captured 11% of the world market. The AXD 301 system includes 1.7 million lines of Erlang: This isn't just some academic language.

Message Passing and Lightweight Processes

Erlang creates its own processes, rather than relying on the underlying operating system to manage processes. They are very lightweight processes, because among other things there is no such thing as a shared variable in Erlang: All communication between processes is done by asynchronous, copy-everything message passing. The basic philosophy here is that each process is completely independent, as if it was running on its own machine, although you can monitor a remote process.

To give you a feel for the numbers, in one of the scalability tests Joe presented it took under a millisecond to create an Erlang process, until there were several thousand processes, and then the creation time jumped to about 5 ms. By comparison, on the same hardware, it took about 250 ms to create processes in C# and Java until there were about 2000 and 1000 processes, respectively, after which no more processes could be created.

In another test, Joe looked at the scalability of message passing times. Erlang had message-passing times under a millisecond well up into the 50,000-process range; C# had times around 15 ms for its full range, and Java started at 15 ms and rose almost exponentially to 100,000 ms once it got over the 100-process mark.

This kind of scalability shows up in the real world as well. A Web server called Yaws (Yet Another Web Server), which spawns one Erlang process for each client request, maintained a throughput of 800 Kbytes/sec up to 80,000 disturbing processes on NFS (network file system), while Apache running on the same system delivered under 400 Kbytes/sec at low numbers, falling off rapidly with numbers of disturbing processes until it crashed at about 4,000 processes.

A Simple Erlang Example

The first example of Erlang in Joe's talk and book is a factorial calculation function. In the following section I'm quoting, mostly from the book. Note carefully in the code below that a period completes a statement, and that a semicolon separates clauses in a statement:

Math.erl:

-module(math1).
-export([factorial/1]).
factorial(0) -> 1;
factorial(N) -> N * factorial(N-1).

Erlang Shell:

> math1:factorial(25).
15511210043330985984000000

Here the function factorial has two defining clauses: the first clause is a rule for computing factorial(0), the second a rule for computing factorial(N). When evaluating factorial for some argument, the two clauses are scanned sequentially, in the order in which they occur in the module, until one of them matches the call. When a match occurs, the expression on the right-hand side of the -> symbol is evaluated, and any variables occurring in the function definition are substituted in the right-hand side of the clause before it is evaluated.

All Erlang functions belong to some particular module. The simplest possible module contains a module declaration, export declarations and code representing the functions which are exported from the module.

Exported functions can be run from outside the module. All other functions can only be run from within the module.

Erlang Types

As you'd expect, Erlang has both integer and floating point numbers. It also has atoms, which are constants with names.

Erlang can create compound data structures using tuples and lists. Tuples are used for storing a fixed number of items and are written as sequences of items enclosed in curly brackets. Tuples are similar to records or structures in conventional programming languages. A few examples of tuples: {a, 12, b}, {}, {1, 2, 3}, and {a, b, c, d, e}.

Lists are used for storing a variable number of items and are written as sequences of items enclosed in square brackets. A few examples of lists: [], [a, b, 12], [22], and [a, 'hello friend'].

Components of tuples and lists can themselves be any Erlang data item including tuples and lists, which allows us to create arbitrary complex structures. The values of Erlang data types can be stored in variables. Variables always start with an upper-case letter.

Erlang has an interesting construct for pattern-matching that I don't have space to cover here, and a large number of built-in functions (BIFs). I consider Erlang most interesting as a language for concurrency, so I'll try to give you a flavor for that.

Concurrency in Erlang

In Erlang, spawn starts a parallel computation (called a process); send sends a message to the mailbox of a process; and receive tries to remove a message from the mailbox of the current process. spawn returns a PID for the process created, and the syntax Pid ! Msg is used to send a message. receive tries to receive a message that fits one of the patterns listed in its clauses, and when it does it performs the matching action.

receive
     Message1 ->
          Actions1;
     Message2 ->
          Actions2;
     ...
     after Time ->
          TimeOutActions
end

If none of the listed patterns are currently in the mailbox, the process is suspended until the receive times out; any messages that don't match the current pattern list are held in the mailbox.

Using named nodes, Erlang steps up from concurrency to distributed operations very easily:

...
Pid = spawn(Fun@Node)
...
alive(Node)
...
not_alive(Node)

Erlang has catch and throw clauses for fault tolerance, and also the ability to monitor a process:

...
process_flag(trap_exit, true),
Pid = spawn_link(fun() -> ... end),
receive
{'EXIT', Pid, Why} ->
...end

The process_flag function, as you might expect, sets a process flag. The spawn_link function spawns a process on a node and creates a link to the process. The process link allows the creating process to receive the exit message from the created process.

...And Lots More

Erlang 5.2/OTP R9B, the current open source distribution as of this writing, includes Mnesia, a heavy duty real-time distributed database; GS, a Graphics System based on Tcl/Tk; and Observer, an application with various facilities for "observing" a live system with minimal disturbance.

I haven't really even begun to scratch the surface of Erlang. I could go on, but by now you should have the idea: Erlang is a practical, major-league, albeit "different," language for concurrent, real-time, distributed fault-tolerant systems.

BYTE.com March 10, 2003


Martin Heller is a Web and Windows programming consultant, an author, and a Senior Contributing Editor at BYTE.com. His most recent publicly viewable project is PC Pitstop. You can reach Martin at MrCLP@mheller.com.


Published by kind permission of the author.