What's the difference between `spawn` and `Task.start` and `Task.async`?

Hello. I’m a beginner engineer.
I’m not sure the difference between spawn and Task.start and Task.async. Although I have read a documentation of Task and Kernel.spawn, I think spawn and Task.start are mostly same…

In the end the Task.async also spawns a process. As mentioned in the docs:

Typically developers do not use the spawn functions, instead they use abstractions such as Task

So the spawn example can be also written with Task:

iex(1)> current = self()
#PID<0.110.0>
iex(2)> child = spawn(fn -> send(current, {self(), 1 + 2}) end)
#PID<0.113.0>
iex(3)> receive do
...(3)>   value -> value
...(3)> end
{#PID<0.117.0>, 3}
iex(4)> task = Task.async(fn -> {self(), 1 + 2} end)
%Task{
  owner: #PID<0.110.0>,
  pid: #PID<0.118.0>,
  ref: #Reference<0.658597441.564396036.165070>
}
iex(5)> Task.await(task)
{#PID<0.118.0>, 3}
2 Likes

The difference is less in the primary functionality of starting another process, but much more in the surrounding context. spawn*ed processes neither implement common OTP functionality (see :proc_lib docs) nor are they supervised. Therefore using those functions is usually discouraged for the ease of leaking processes in case of failures.

Tasks on the other hand are proper OTP processes using :proc_lib as well as started under a supervisor, so properly cleanup up if necessary.

9 Likes

Thank you :smiley: