vrod

vrod

Hello! I am studying the Task module and I am trying to teach myself some patterns of concurrency in Elixir. I found something like this while reading the documentation for Process.sleep/1:

Task.start_link(fn ->
      Process.sleep(:timer.seconds(1))
      send(parent, :work_is_done)
end)

receive do
  :work_is_done -> IO.puts("Task complete!")
after
  2_000 -> IO.puts("Operation timed out.")
end

My question is: is this the same as using Task.async?


async_task = Task.async(fn ->
      Process.sleep(:timer.seconds(1))
      :work_is_done
end)

val = Task.await(async_task)
IO.inspect(val)
# :work_is_done

So this gives me 3 questions (related) that I hope someone can explain to me:

  1. Does Task.await function the same way as the send + receive example? (I like the syntax of Task.async and Task.await, but I want to make sure this is only syntax difference)
  2. I tried doing send/recieve from Task.start/1 and it seems to work the same as Task.start_link/1. Is there case where Task.start/1 must be used or case where Task.start_link/1 must be used?
  3. If I have a list of tasks, is it always better to use Task.async_stream? I tried using Enum.map to put many Task.asyncs together and it seems like Task.async_stream is a better way.

Thank you! I want to try to understand this well before I study GenServers.

First 4 of 4 Posts Switch mode

lovyou

lovyou

  1. Generally yes. There is more stuff that is done underneath but at the end we use send and receive. The same information you can find in the documentation:

One of the common uses of tasks is to convert sequential code into concurrent code with Task.async/1 while keeping its semantics. When invoked, a new process will be created, linked and monitored by the caller. Once the task action finishes, a message will be sent to the caller with the result.

  1. Yes, you use start_link instead of start when you want to start a process linked to the current process. You can find more information about linking here: https://elixir-lang.org/getting-started/processes.html#links.

  2. Yes, Task.async_stream be first thing to consider. If it doesn’t meet your requirements, then you can combine Task.async with Enum/Stream functions.

vrod

vrod OP

Thank you for your response! I think this is beginning to make sense.

ityonemo

ityonemo

It’s not exactly the same. Task.async is a bit smarter than that, because when you call it it saves a reference. When the await catches the message, it pattern matches against the reference to make sure it’s matching against the right task.

This protects against the situation where tasks cross streams. In the Task implementation, you can do this:

1..10
|> Enum.map(&Task.async(fn ->
  Process.sleep(Enum.random(1..200))
  &1
end))
|> Enum.map(&Task.await/1)

And your 1..10 will come back in order; they will not with your await implementation.

Check the elixir code for task.await: elixir/lib/elixir/lib/task.ex at v1.10.4 · elixir-lang/elixir · GitHub

This pattern will reappear in gen_server.call, so understanding it is probably a good idea :smiley:

ityonemo

ityonemo

Also, if you’re still early on, Task is kind of still only the first layer on top of spawn. I use it a lot in tests, but I think for anything that hits prod you should consider Task.Supervised functions. It may not be necessary to fully understand yet depending on where you are in elixir learning.

— All posts loaded —

Where Next? Top

Trending in Questions Top

stjefim
Hello! Suppose you are building workflow (order / task / payment) processing system with the following requirements: Each workflow con...
New
jonnycharles
I’m in search of an Elixir library that offers PDF generation capabilities similar to Ruby’s Prawn. While there have been discussions abo...
New
spammy
I’m looking to build a personal workflow to quickly deploy web applications written in elixir/phoenix, for local consumption (ie not on t...
New
dli
Before I dive in myself, did anyone successfully sprinkle Hologram into their existing LiveView app? Looking for hints regarding: Addi...
New
roeland
Kia ora, We have been using elixir-google-api to connect to Google Drive. However, with the updates to Tesla due to CVEs this is now bro...
New
bottlenecked
Hi all, I wanted to ask how the community is dealing with post-release steps. Today we have Ecto migrations, which make sure that the db...
New
rahultumpala
Hello, I have an Elixir backend that implements a custom protocol over TCP. I want to load test the backend and assess the performance o...
New

Other Trending Topics Top

JesseHerrick
Hey, I’m Jesse and I’m the main contributor behind Dexter, a full-featured, lightning-fast Elixir LSP optimized for large codebases. It s...
New
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
Damirados
Hello everyone. After busy few months I am happy to announce v0.1.0 of Emerge & Solve. They are GUI (Emerge) and State management (S...
New
netoum
Corex is an accessible, unstyled UI component library for Phoenix that integrates Zag.js state machines using Vanilla JavaScript and Live...
New
ausimian
Emily is an Elixir library that runs Nx computations on Apple’s MLX. Install it as the default Nx backend and Nx, defn, Axon, Nx.Serving,...
New
juhalehtonen
There has been a thread to discuss the Stack Overflow Developer Survey on this forum every year since 2018, so here’s yet another one for...
New

We're in Beta

About us Mission Statement