В примере глубоких обработчиков из документации есть такой абзац:
Вычисление f само может выполнять эффекты. Когда f выполняет Yield, его задача приостанавливается и помещается в очередь готовых задач, а планировщик запускает следующую задачу из очереди. Если эффект — Fork f, текущая задача приостанавливается, а новая задача f сразу выполняется хвостовым вызовом spawn f. Обратите внимание, что запускать новую задачу первой — произвольное решение. Можно было бы вместо этого поместить задачу f в очередь готовых задач и сразу продолжить k.
Возможно, я упускаю что-то простое, но рассмотрим такой пример планировщика:
type _ Effect.t += Fork : (unit -> unit) -> unit t
| Yield : unit t
(* Round-robin scheduling with concurrency *)
let run (entry : unit -> unit) : unit =
let pending : (int * (int, unit) continuation) option ref =
ref None (* exchanger awaiting a partner *)
in
let ready = Queue.create () in (* ready-task queue *)
let schedule cont arg =
let resume () = continue cont arg in
Queue.push
resume ready
in
let next () =
if Queue.is_empty ready then () (* finished *)
else begin
let resume = Queue.pop ready in
resume ()
end
in
let rec start (work : unit -> unit) : unit =
match work () with
| () -> next ()
| exception err ->
print_endline (Printexc.to_string err);
next ()
| effect Yield, cont -> schedule cont (); next ()
(* How can work be queued at this point? *)
| effect (Fork work), cont -> schedule cont (); start work
| effect (Xchg value), cont ->
begin match !pending with
| Some (other, saved) -> pending := None; schedule saved value; continue cont other
| None -> pending := Some (value, cont); next ()
end
in
start entry
Как поместить work в ready?