1
1
(* * Direct style control flow for Lwt.
2
2
3
- This module relies on OCaml 5's
4
- {{:https://ocaml.org/manual/5.3/effects.html} effect handlers}.
5
- Instead of chaining promises using {!Lwt.bind} and {!Lwt.map}
6
- and other combinators, it becomes possible to start
7
- lightweight "tasks" using [Lwt_direct.spawn (fun () -> ...)].
8
- The body of such a task is written in direct-style code,
9
- using OCaml's standard control flow structures such as loops,
10
- higher-order functions, exception handlers, [match], etc.
11
-
12
- Interactions with the rest of lwt can be done using [await],
13
- for example:
3
+ Using this module you can write code in direct style (using loops,
4
+ exceptions handlers, etc.) in an Lwt codebase. Your direct-style sections
5
+ must be enclosed in a call to {!spawn} and they may {!await} on promises.
6
+ For example:
14
7
15
8
{[
16
- Lwt_direct.spawn (fun () ->
9
+ open Lwt_direct
10
+ spawn (fun () ->
17
11
let continue = ref true in
18
12
while !continue do
19
- match Lwt_io.read_line in_channel |> Lwt_direct.await with
13
+ match await @@ Lwt_io.read_line in_channel with
20
14
| exception End_of_file -> continue := false
21
15
| line ->
22
16
let uppercase_line = String.uppercase_ascii line in
23
- Lwt_io.write_line out_channel uppercase_line |> Lwt_direct.await
17
+ await @@ Lwt_io.write_line out_channel uppercase_line
24
18
done)
25
19
]}
26
20
27
- This code snippet contains a simple "task" that repeatedly reads
28
- a line from a [Lwt_io] channel, uppercases it, and writes the
29
- uppercase version to another channel.
21
+ In this code snippet, the [while]-loop repeats a simple task of reading from
22
+ an {!Lwt_io.channel}, modifying it, and writing it to a different channel.
23
+ The code is in direct-style: the control structures are standard OCaml
24
+ without any Lwt primitives.
30
25
31
- This task is itself a [unit Lwt.t], which is resolved when the function
32
- returns. It is possible to use
33
- {!Lwt_direct.run_in_the_background} to ignore the result and
34
- let the task run in the background instead .
26
+ The code-snippet as a whole is a [unit Lwt.t] promise. It becomes resovled
27
+ when the function returns. Conversely, the promises inside the snippet are
28
+ wrapped in {!await}, turning them into regular plain (non-Lwt) values
29
+ (although values that are not available immediately) .
35
30
36
- *)
31
+ The [Lwt_direct] module is implemented using OCaml 5's
32
+ {{:https://ocaml.org/manual/5.3/effects.html} effects and effect handlers}.
33
+ This allows the kind of scheduling where a promise is turned into a regular
34
+ value and vice-versa. *)
37
35
38
36
val spawn : (unit -> 'a ) -> 'a Lwt .t
39
- (* * [spawn f] runs the function [f ()] in a task within
40
- the [Lwt_unix] event loop. [f ()] can create [Lwt]
41
- promises and use {!await} to wait for them. Like any promise
42
- in Lwt, [f ()] can starve the event loop if it runs long computations
43
- without yielding to the event loop.
37
+ (* * [spawn f] runs the function [f ()], it also returns a promise [p] which is
38
+ resolved when the call to [f ()] returns a value. If [f ()] throws an
39
+ exception, the promise [p] is rejected.
40
+
41
+ The function [f] can create Lwt promises (e.g., by calling functions from
42
+ [Lwt_io], [Lwt_unix], or third-party libraries) and use {!await} to wait for
43
+ them. These promises are evaluated in the Lwt event loop.
44
+
45
+ Like any promise in Lwt, [f ()] can starve the event loop if it runs long
46
+ computations without yielding to the event loop.
47
+
48
+ Cancelling the promise returned by [spawn] has no effect: the execution of
49
+ [f ()] continues and the promise is not cancelled.
44
50
45
51
When [f ()] terminates (successfully or not), the promise
46
52
[spawn f] is resolved with [f ()]'s result, or the exception
@@ -50,32 +56,43 @@ val spawn_in_the_background :
50
56
(unit -> unit ) ->
51
57
unit
52
58
(* * [spawn_in_the_background f] is similar to [ignore (spawn f)].
53
- The computation [f()] runs in the background in the event loop
59
+ The computation [f ()] runs in the background in the event loop
54
60
and returns no result.
61
+
55
62
If [f()] raises an exception, {!Lwt.async_exception_hook} is called. *)
56
63
57
64
val yield : unit -> unit
58
65
(* * Yield to the event loop.
59
66
60
- Calling [yield] outside of {!spawn} or {!run_in_the_background} will raise an exception,
61
- crash your program, or otherwise cause errors. It is a programming error to do so. *)
67
+ This is similar to [await (Lwt.pause ())], using less indirection internally
68
+ and fewer characters to write.
69
+
70
+ Calling [yield] outside of {!spawn} or {!spawn_in_the_background} will raise
71
+ an exception, crash your program, or otherwise cause errors. It is a
72
+ programming error to do so. *)
62
73
63
74
val await : 'a Lwt .t -> 'a
64
- (* * [await prom] returns the result of [prom], or re-raises the
65
- exception with which [prom] failed if it failed.
66
- If [prom] is not resolved yet, [await prom] will suspend the
67
- current task and resume it when [prom] is resolved.
75
+ (* * [await p] returns the result of [p] (or raises the exception with which [p]
76
+ was rejected.
77
+
78
+ If [p] is not resolved yet, [await p] will suspend the current task (i.e.,
79
+ the computation started by the surrounding {!spawn}) and resume it when [p]
80
+ is resolved.
68
81
69
- Calling [await] outside of {!spawn} or {!run_in_the_background} will raise an exception,
70
- crash your program, or otherwise cause errors. It is a programming error to do so. *)
82
+ Calling [await] outside of {!spawn} or {!spawn_in_the_background} will raise
83
+ an exception, crash your program, or otherwise cause errors. It is a
84
+ programming error to do so. *)
71
85
72
86
(* * Local storage.
73
87
74
88
This storage is the same as the one described with {!Lwt.key},
75
89
except that it is usable from the inside of {!spawn} or
76
- {!run_in_the_background}.
90
+ {!spawn_in_the_background}.
91
+
92
+ Each task has its own storage, independent from other tasks or promises.
77
93
78
- Each task has its own storage, independent from other tasks or promises. *)
94
+ NOTE: it is recommended to use [Lwt_direct.Storage] functions rather than
95
+ [Lwt.key] functions from {!Lwt}. The latter is deprecated. *)
79
96
module Storage : sig
80
97
type 'a key = 'a Lwt .key
81
98
val new_key : unit -> 'a key
0 commit comments