Elm concurrent tasks

The latest elm radio - elm-concurrent-task with Andrew MacMurray - was a good listen and an interesting technical solution to the surprising fact that Task.mapX is as sequential as … Task.sequence and Task.andThen. The starting discussion noted that parallel tasks with individual callbacks is generally the ‘javascript way’.

But the elephant in the podcast was why there is no momentum to addressing this un-intuitive situation, or at least the adding of an option for parallelization.

This is when Elm becomes frustrating. Things aren’t always right, but there’s no questioning of them, and little prospect of improvement.


Why would you expect any parallelism out of Task.map? There isn’t more than one thing that could be parallelized.

I think they meant map2 and friends.

1 Like

Ah, that makes sense, and it’s also surprising to me that it wouldn’t be parallel!

It seems to me that elm-concurrent-task itself is “momentum to addressing this un-intuitive situation, or at least the adding of an option for parallelization”, so I’m not sure I understand what the OP is getting at.


It is also clearly stated in the documentation:

Note: Say we were doing HTTP requests instead. map2 does each task in order, so it would try the first request and only continue after it succeeds. If it fails, the whole thing fails!

yes it was a typo as @gampleman pointed out.
@uweg - it might be documented, but it is still un-expected absent of reading the docs, and fundamentally slows all Elm apps down that could leverage parallel cmds (Elm will lose some speed comparisons for this alone)

I wonder… are we talking about parallel or asynchronous here?

If I have parallel computations running, they are going to be running at the same time on my system. So >1 CPU will be active. This is generally what I understand by the term parallel, since it is frequently used in conjunction with talking about parallel processing.

If I have asynchronous processes, they could be running in sequence, or in parallel, so 1 CPU core or >1 CPU core. Synchronous processes could also be running in parallel with thread operators such as spawn and join.

I suppose we had better think about the term concurrent also. Its sort-of the same thing as parallel, except maybe not. The user could be moving their mouse concurrently to waiting for some HTTP request to complete. The mouse and the HTTP request are not processing jobs that happen on my machine, their are concurrent tasks happening in the real world, outside of my machine. So its a bit different than what I normally associate with the word parallel.

So I think we are talking about concurrent asynchronous event handling here.

Javascript in the browser is single threaded, so there is no parallel execution. Its programming model is asynchronous though. There are web workers that can run parallel CPU jobs in the browser, it is also worth noting. Web workers programming model is awkward and certainly not ideal for concurrent functional programming where you might want to be able to pass continuations between threads - it does not allow this.

To give an example, suppose I want to GET 2 HTTP endpoints. If I create 2 tasks, one for each, and run then with Task.map2. The docs say:

Note: Say we were doing HTTP requests instead. map2 does each task in order, so it would try the first request and only continue after it succeeds. If it fails, the whole thing fails!”

map2 : (a -> b -> result) -> Task x a -> Task x b -> Task x result
map2 func taskA taskB =
    |> andThen (\a -> taskB
    |> andThen (\b -> succeed (func a b)))

It certainly seems possible that map2 could execute the 2 asynchronous tasks concurrently, then join and combine their results once both have completed. It also seems correct that andThen always processes sequentially, not starting the second task until the output of the first one completes. Presumably map2 could be re-written as a special case not making use of andThen.

Would be interesting to see in code how this could be done? A hypothetical kernel function for example, can anyone write it to show how?

Does this run 2 Tasks concurrently? Process - core 1.0.5 . The description in the docs certainly seems to be suggesting that it does:

" Run a task in its own light-weight process. In the following example, task1 and task2 will be interleaved. If task1 makes a long HTTP request or is just taking a long time, we can hop over to task2 and do some work there.

spawn task1
  |> Task.andThen (\_ -> spawn task2)

Note: This creates a relatively restricted kind of Process because it cannot receive any messages. More flexibility for user-defined processes will come in a later release!"

There was a fair amount of discussion around parallel vs concurrent in the naming of elm-concurrent-task with Andrew MacMurray, along with parts of elm-pages. Technically JS runs concurrently, though maybe with workers you could run in parallel?

As for Elm’s Task.mapN, it would be nice to have a concurrent/parallel implementation as well as the sequential one. Sequential is nice when you only want the subsequent calls to happen if the priors succeed. Like a map7 where the first task fails, I wouldn’t then want 6 expensive tasks to continue processing.

I’m not sure what’s wrong here, the docs are explicit and I’d argue there is no intuitive way to interpret whether a function is sequential or parallel. Either the function name is explicit, or you have to read the docs.

Just to be clear, when I do Task.mapX and see in the chrome dev console that the second task does not event start until the first one finishes, I could move it all to commands and then write boilerplate to wait until all X task have completed, or I could implement elm-concurrent-task, or I could wonder why the default Elm behaviour is not completely ‘delightful’.

(Yes, if there’s a strong chance of failure, then perhaps doing the riskiest first is reasonable, but I’m thinking about a set of calls to my server to initialise my app. Yes then I could even ask the backend team to provide a route that groups them, but that’s feels rather brittle)

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.