Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cookbook basic concurrency recipe #2377

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions data/cookbook/concurrency-misc/00-lwt.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
---
packages:
- name: lwt
tested_version: 5.7.0
used_libraries:
- lwt
- lwt.unix
discussion: |
- **Understanding `Lwt`:** Lwt is a scheduler that permits concurrent execution of promises on a single thread. Promise switching is performed at each long I/O (using the `Lwt_io` module), timing pause (`Lwt_unix.sleep`), or explicit promise switching (`Lwt.pause ()`). Promises are typically composed with the `Lwt.bind` function. More details about the monad `bind` function is given in the [monad section](/docs/monads). The `let` operators are detailed in the [operator section](/docs/operators). We can refer to [the Lwt manual](https://ocsigen.org/lwt/latest/manual/manual).
- **Alternative Libraries:** Lwt is perhaps the most-used concurrent library (It is used in Ocsigen and Dream, for example). `async` is a similar library. With OCaml 5, the multithreading permits the definition of the `eio` library which doesn't need monads. Other schedulers are `miou` and `riot` (with Erlang style message passing).
---

(* Some useful `let` operators. The construction `let* a = <Lwt promise> in b` means schedule the Lwt promise, wait for its result, then excute `b` where all occurence of `a` are replaced by the result. The construction `let*? a = <promise> in b` has the same result, but when the Lwt promise has finished, it continues if the result is `Ok x` (then `a` are replaced by `x`), and stops if `Error err`. *)
let ( let* ) = Lwt.bind
let ( let*? ) = Lwt_result.bind

(* `both` schedules two promises concurently. *)
let task n =
let* () = Lwt_io.printf "Task %d - first line\n" n in
let* () = Lwt.pause () in
let* () = Lwt_io.printf "Task %d - second line\n" n in
Lwt.return n
let (_result1, _result2) =
Lwt_main.run @@ Lwt.both (task 1) (task 2)

(* When having a promise function that should be scheduled multiple times with different values, `iter_p`, `iter_s`, `map_p`, and `map_s` schedule one promise per item from a given list. The `_s` versions schedule the promises sequentialy, and `_p` schedules them in parallel. `iter_*` returns `()` (and expects tasks that return a unit Lwt) while `map_*`returns the list of results. *)
let _result_list =
Lwt_main.run @@ Lwt_list.map_p task [1; 2; 3]
let _result_list =
Lwt_main.run @@ Lwt_list.map_s task [1; 2; 3]
let task' n =
let* _result = task n in
Lwt return ()
let () =
Lwt_main.run @@ Lwt_list.iter_p task' [1; 2; 3]
let () =
Lwt_main.run @@ Lwt_list.iter_s task' [1; 2; 3]

(* `sleep seconds` pauses for then given seconds number. *)
let () =
Lwt_main.run @@ Lwt_unix.sleep 1.
2 changes: 2 additions & 0 deletions data/cookbook/tasks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ categories:
slug: spawn-a-thread-and-receive-a-response
- title: Pass Data Between Parallel Threads
slug: pass-data-between-parallel-threads
- title: Miscellaneous
slug: concurrency-misc
- title: Cryptography
tasks:
- title: Calculate the SHA-256 Digest of a File
Expand Down
Loading