Too many 'hello world's
First, at the repl:
1> io:fwrite("Hello, world!~n").
Hello, world!
ok
2> erlang:display('hello world').
'hello world'
true
3> io:fwrite(<<"Hello, ~s!\n">>, [<<"world">>]).
Hello, world!
ok
Second, at the command line:
$ erl -eval 'io:fwrite("Hello, world!~n"), halt()' -noshell
Hello, world!
And then,
- a module with a function that does proper I/O
- printing a term ... potentially really fast
- an escript
- a rebar3 escript
a module with a function that does proper I/O
-module(h1).
-export([hello/0, hello/1]).
hello() -> hello("world").
hello(Name) -> io:fwrite("Hello, ~s!~n", [Name]).
This can be used interactively:
1> c(h1).
{ok,h1}
2> h1:hello().
Hello, world!
ok
3> h1:hello("something else").
Hello, something else!
ok
Or by slowly spawning an Erlang node just to call this function:
$ getr 1 erl -noinput -s h1 hello -s init stop Hello, world! User time : 0 s, 287410 us System time : 0 s, 89129 us Time : 376 ms (376.000 ms/per) Max RSS : 47.1 MB Page reclaims : 8625 Page faults : 0 Block inputs : 0 Block outputs : 0 vol ctx switches : 1952 invol ctx switches : 3846
You can shave a bit off the VM off:
$ getr 1 erl +S 1 +SDio 1 +P 1024 +Q 1024 -mode minimal -noinput -s h1 hello -s init stop Hello, world! User time : 0 s, 70231 us System time : 0 s, 21882 us Time : 92 ms (92.000 ms/per) Max RSS : 32.4 MB Page reclaims : 5883 Page faults : 0 Block inputs : 0 Block outputs : 0 vol ctx switches : 538 invol ctx switches : 0
Those flags are explained by erl -man erl:
- limits schedulers to 1, from a CPU-determined number
- drop Dirty I/O schedules to 1, from 10
- set max processes to 1024, from 262144 (2^18)
- set max ports to 1024, from 8192 (windows) or 65536
- sets mode to an undocumented alternative used by
erlc
printing a term ... potentially really fast
-module(h2).
-export([start/0]).
start() ->
erlang:display('Hello world!').
This can be used just like the last example, but what makes it interesting is that AtomVM can use this but not the last example. This is a tiny Erlang VM, an alternative to the BEAM machine, that targets embedded devices.
$ erlc h2.erl $ ~/erlang/AtomVM/build/tools/packbeam/PackBEAM h2.avm h2.beam $ getr 1 ~/erlang/AtomVM/build/src/AtomVM h2.avm Hello world! Return value: true User time : 0 s, 1199 us System time : 0 s, 0 us Time : 1 ms (1.000 ms/per) Max RSS : 2.9 MB Page reclaims : 99 Page faults : 0 Block inputs : 0 Block outputs : 0 vol ctx switches : 1 invol ctx switches : 0
Hyperfine says that's about 2266.99 +/- 1666.11 times faster than erl -noinput -s h2 start -s init stop.
an escript
#! /usr/bin/env escript
main(_) -> io:fwrite("Hello, world!~n").
As used:
$ chmod +x h3 $ ./h3 Hello, world!
There are no performance benefits to using an escript, but this has all the usual subtle administrative benefits of a script:
- it's very easy to invoke: you just run it. There's no separate command to run that starts it.
- it's very easy to investigate: you just open it. The source is right there, and possibly even the documentation. You do not have to go hunting for the source code.
a rebar3 escript
$ rebar3 new escript h4 $ cd h4 $ rebar3 escriptize $ ./_build/default/bin/h4 hello world Args: ["hello","world"]
The 'h4' file in this case is binary, containing a zip archive of the project's .app and .beam files, but a value of a rebar3 escript is that you can include multiple files into the script. Let's demonstrate that by editing src/h4.erl,
-module(h4).
-export([main/1]).
main(_) ->
greeter:greet(world),
erlang:halt(0).and adding a new src/greeter.erl,
-module(greeter).
-export([greet/1]).
greet(X) -> io:fwrite("Hello, ~p!\n", [X]).
With these changes, the usage is the same:
$ rebar3 escriptize $ ./_build/default/bin/h4 hello world Hello, world!
Another value of a rebar3 escript is that it's always compiled, which can enormously improve Erlang performance, but as of Erlang/OTP 27 and #7348 all escripts are compiled by default. Now, rebar3 is only saving you some compile-time.