Zulip Chat Archive

Stream: lean4

Topic: waiting on a List of Tasks


Scott Morrison (Apr 19 2023 at 07:41):

Given a List (Task α), is there any way to find if one is ready?

Eric Wieser (Apr 19 2023 at 08:26):

On a similar note, do we have a way to go from List (Task X) to Task (List X)?

Scott Morrison (Apr 19 2023 at 09:41):

Isn't that just

example (L : List (Task X)) : Task (List X) :=
  Task.spawn fun _ => L.map Task.get

Eric Wieser (Apr 19 2023 at 11:01):

Doesn't that run them sequentially rather than in parallel?

Alex Keizer (Apr 19 2023 at 11:13):

I think tasks run in the background as soon as they're created. Task.get is not driving the task, it's just checking whether the background computation has finished. At least, that is my interpretation of the following doc:

/--
`spawn fn : Task α` constructs and immediately launches a new task for
evaluating the function `fn () : α` asynchronously.

`prio`, if provided, is the priority of the task.
-/
@[noinline, extern "lean_task_spawn"]
protected def spawn {α : Type u} (fn : Unit  α) (prio := Priority.default) : Task α :=
  fn ()⟩

Eric Wieser (Apr 19 2023 at 11:16):

Ah, sorry for the noise then

Mac Malone (Apr 23 2023 at 17:41):

Scott Morrison said:

Isn't that just

example (L : List (Task X)) : Task (List X) :=
  Task.spawn fun _ => L.map Task.get

While simple, this is inefficient. It spawns a thread solely to wait on others, which is a waste of resources. Ideally, you would use a bind to merge the tasks into one.

Wojciech Nawrocki (Apr 23 2023 at 18:33):

Task.spawn with default priority won't spawn a dedicated thread iirc, so that's not so much of an issue. The real problem is that calling Task.get from within another task does not register a dependency with the task manager, so this code can deadlock

Wojciech Nawrocki (Apr 23 2023 at 18:38):

Unfortunately as far as waiting on a list of Tasks goes, you may have to write the code yourself using docs4#Task.bind or docs4#IO.bindTask . At one point I wrote docs4#IO.AsyncList which can do this for you in cases where your computation is producing a list of tasks, kind of like a coinductive stream. However not all computations can be sensibly phrased this way.

Wojciech Nawrocki (Apr 23 2023 at 18:39):

Oh, if you just want to find if one is ready, there is docs4#IO.waitAny. The method that's missing would be IO.waitAll.

Wojciech Nawrocki (Apr 23 2023 at 18:40):

@Scott Morrison ^

Eric Wieser (Apr 23 2023 at 18:47):

It looks like the API of waitAny is rather lacking; I'd expect it to either return a list of the non-resolved tasks, or the index of the one that was resolved

Wojciech Nawrocki (Apr 23 2023 at 19:30):

Yeah, it's very low-level. You can easily create the index yourself, though, by returning it from the task.

Eric Wieser (Apr 23 2023 at 20:19):

Well, the low-level API in C already has the index available as it holds a reference to the task object rather than just its result

Eric Wieser (Apr 23 2023 at 20:19):

But I see your point

Sebastian Ullrich (Apr 23 2023 at 21:30):

Wojciech Nawrocki said:

Oh, if you just want to find if one is ready, there is docs4#IO.waitAny. The method that's missing would be IO.waitAll.

In contrast to waitAny, you can build a reasonably efficient version of waitAll using bindTask

Adam Topaz (Apr 23 2023 at 21:43):

Mac said:

Scott Morrison said:

Isn't that just

example (L : List (Task X)) : Task (List X) :=
  Task.spawn fun _ => L.map Task.get

While simple, this is inefficient. It spawns a thread solely to wait on others, which is a waste of resources. Ideally, you would use a bind to merge the tasks into one.

Would using docs4#List.mapA be the right approach?

Eric Wieser (Apr 23 2023 at 21:47):

Is that different to docs4#List.traverse ?

Adam Topaz (Apr 23 2023 at 21:48):

For some reason the docs webpage isn’t letting me look at the source of that function.

Eric Wieser (Apr 23 2023 at 21:49):

I think source links are broken for all of mathlib

Eric Wieser (Apr 23 2023 at 21:50):

These lines are failing, cc @Henrik Böving

Henrik Böving (Apr 23 2023 at 21:53):

Ah, doc-gen is not capable of understanding that a dependnecy that is given as a directory instead of a git thing in lake is an issue, that's annoying, I'll try to fix the action

Henrik Böving (Apr 23 2023 at 22:18):

Okay I pushed a fix to doc-gen and tested it locally, the source links should work again with the next build so in at max 9 hours

Henrik Böving (Apr 23 2023 at 22:33):

Ah no! the mathlib4 dooc-gen4 build is failing due to some other weird reason that I dont have influence on from the doc-gen4 repo so you might have to wait a little longer until that is fixed as well.

Scott Morrison (Apr 24 2023 at 12:47):

Ah, waitAll is essentially already there as BaseIO.mapTasks pure : List (Task α) → BaseIO (Task (List α)).

Scott Morrison (Apr 24 2023 at 12:49):

!4#3620 has waitAny', which also returns the remaining tasks, and sequenceTasks := BaseIO.mapTasks pure.

Eric Wieser (Apr 24 2023 at 13:05):

Is "traverse" a better word than "sequence"? nevermind


Last updated: Dec 20 2023 at 11:08 UTC