Async and recursive loop

It is obvious that such a solution will not work, because the scheduler is launched only after the program exits the loop at the 100th iteration.

It actually is not because of this. Rather you are running into the issue of code between binds cannot be interrupted. The whole loop will iterate until it is done because there is no bind or something like that to allow some other work (like that created with submit_async_task) to be scheduled and determined.

To let the behavior that I think you’re looking for happen (eg, the thing printing to the screen 1 second after the proper iteration rather than way at the end), one way is you could add in a bind point with a short wait in your loop.

let rec loop count =
  Stdio.printf "Iter %d\n%!" count ;
  start_heavy_computation count ;
  match count with
  | _ when count = 5 ->
      submit_async_task () ;
      loop (count + 1)
  | _ when count = 100 ->
      return ()
  | _ ->
      (* Right here will allow your other jobs to get scheduled and determined. *)
      after (Core.Time_float.Span.of_ms 100.) 
      >>= fun () -> loop (count + 1)

Then you will get something like this:

Iter 1                             
Iter 2
Iter 3
Iter 4
Iter 5
submit_async_task
Iter 6
Iter 7
Iter 8
Iter 9
Iter 10
Iter 11
Executing Async task
Async task executed
Iter 12
Iter 13
Iter 14
Iter 15
...
...

Which I think is what you’re after.