# Lwt, message queue, multiple writer, single reader

**URL:** <https://discuss.ocaml.org/t/lwt-message-queue-multiple-writer-single-reader/2567>\
**Category:** Learning\
**Tags:** lwt\
**Created:** [September 17, 2018, 10:10am UTC](https://discuss.ocaml.org/t/lwt-message-queue-multiple-writer-single-reader/2567 "2018-09-17T10:10:46Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![thomas\_ridge](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/thomas_ridge/32/1478_2.png) [@thomas\_ridge](https://discuss.ocaml.org/u/thomas_ridge)\
**Post date:** [September 17, 2018, 10:10am UTC](https://discuss.ocaml.org/t/lwt-message-queue-multiple-writer-single-reader/2567/1 "2018-09-17T10:10:46Z")

</div>

Dear All,

I want to write some Lwt code, where there is a single “reader thread” that services messages, and multiple “writer threads” that create messages. I want the messages from the writers to go on a queue and be served by the reader thread in FIFO order.

Using system threads, it is possible to construct such a queue using mutexes and condition variables.

My question is: Is there an equivalent “inter-thread message queue” for Lwt? I’m aware of Lwt\_stream, and the suggestion to use Lwt\_pipe, but from very brief scanning of the code, both look a bit complicated for what I want. But perhaps I should just use Lwt\_pipe anyway?

---

<div class="post-metadata">

**Author:** ![thomas\_ridge](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/thomas_ridge/32/1478_2.png) [@thomas\_ridge](https://discuss.ocaml.org/u/thomas_ridge)\
**Post date:** [September 17, 2018, 1:18pm UTC](https://discuss.ocaml.org/t/lwt-message-queue-multiple-writer-single-reader/2567/2 "2018-09-17T13:18:28Z")

</div>

Using OCaml’s threads library I wrote this, which is basically what I want (but I was hoping for something for Lwt):

> **[tomjridge/tjr\_mem\_queue](https://github.com/tomjridge/tjr_mem_queue)**
>
> An in-memory message queue for messaging between senders and a receiver. - tomjridge/tjr\_mem\_queue

---

<div class="post-metadata">

**Author:** ![thomas\_ridge](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/thomas_ridge/32/1478_2.png) [@thomas\_ridge](https://discuss.ocaml.org/u/thomas_ridge)\
**Post date:** [September 17, 2018, 4:23pm UTC](https://discuss.ocaml.org/t/lwt-message-queue-multiple-writer-single-reader/2567/3 "2018-09-17T16:23:33Z")

</div>

I suppose if I replicate the code in Lwt, using the standard Queue module, this will work fine? And I can avoid some of the locking as well since I know Lwt threads are copperative.

---

<div class="post-metadata">

**Author:** ![thomas\_ridge](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/thomas_ridge/32/1478_2.png) [@thomas\_ridge](https://discuss.ocaml.org/u/thomas_ridge)\
**Post date:** [September 17, 2018, 7:07pm UTC](https://discuss.ocaml.org/t/lwt-message-queue-multiple-writer-single-reader/2567/4 "2018-09-17T19:07:22Z")

</div>

I added an Lwt version of the code in the repo above.

Benchmarking indicated that the Lwt version was about 2.5 times slower than the native OCaml thread version, which was a bit unexpected. This may be because the Lwt scheduler seems to be fairer than the native pre-emptive thread scheduler, resulting in more thread transitions.

---

<div class="post-metadata">

**Author:** ![antron](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/antron/32/62_2.png) [@antron](https://discuss.ocaml.org/u/antron)\
**Post date:** [September 19, 2018, 3:07pm UTC](https://discuss.ocaml.org/t/lwt-message-queue-multiple-writer-single-reader/2567/5 "2018-09-19T15:07:11Z")

</div>

@thomas_ridge, the Lwt test is slower because it is calling `Lwt.pause` too often.

If all the “tasks” in an Lwt program are “asleep” (loosely speaking), Lwt checks for I/O. Your three writers put themselves to “sleep” with `Lwt.pause` after each enqueue. As a result, Lwt is making one call to `select`/`epoll`/`kevent` for each three (actually, six) enqueues. That’s why it’s very slow.

I [opened a PR](https://github.com/tomjridge/tjr_mem_queue/pull/1/commits/071360c2a4db1fdf74e0528485447b973b30951f) that makes the Lwt test go about 10x faster. It has each writer do 1000 enqueues before calling `Lwt.pause`.

So, basically, with Lwt, if you have a CPU-bound “task,” you should avoid calling `Lwt.pause` in it too often  
🙂

We’ve had some problems with this in the past, so maybe Lwt should be more intelligent about whether, at each iteration, it chooses to poll for I/O, or resume paused tasks.

---

<div class="post-metadata">

**Author:** ![antron](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/antron/32/62_2.png) [@antron](https://discuss.ocaml.org/u/antron)\
**Post date:** [September 19, 2018, 3:17pm UTC](https://discuss.ocaml.org/t/lwt-message-queue-multiple-writer-single-reader/2567/6 "2018-09-19T15:17:05Z")

</div>

> maybe Lwt should be more intelligent

I opened an issue for addressing this in the near future: [Improve performance in CPU-bound programs · Issue #622 · ocsigen/lwt · GitHub](https://github.com/ocsigen/lwt/issues/622)

---

<div class="post-metadata">

**Author:** ![thomas\_ridge](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/thomas_ridge/32/1478_2.png) [@thomas\_ridge](https://discuss.ocaml.org/u/thomas_ridge)\
**Post date:** [September 20, 2018, 7:59am UTC](https://discuss.ocaml.org/t/lwt-message-queue-multiple-writer-single-reader/2567/7 "2018-09-20T07:59:30Z")

</div>

@antron Thank you for the feedback. Your explanation makes sense.

If I didn’t have any pauses, will Lwt still execute each thread reasonably often?

---

<div class="post-metadata">

**Author:** ![thomas\_ridge](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/thomas_ridge/32/1478_2.png) [@thomas\_ridge](https://discuss.ocaml.org/u/thomas_ridge)\
**Post date:** [September 20, 2018, 9:20am UTC](https://discuss.ocaml.org/t/lwt-message-queue-multiple-writer-single-reader/2567/8 "2018-09-20T09:20:19Z")

</div>

@antron Actually I’m not sure I understand… why is Lwt trying to use select/epoll/kevent? There isn’t any I/O happening here.

Unless… are mutexes and condition vars implemented this way somehow?

---

<div class="post-metadata">

**Author:** ![thomas\_ridge](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/thomas_ridge/32/1478_2.png) [@thomas\_ridge](https://discuss.ocaml.org/u/thomas_ridge)\
**Post date:** [September 20, 2018, 9:26am UTC](https://discuss.ocaml.org/t/lwt-message-queue-multiple-writer-single-reader/2567/9 "2018-09-20T09:26:26Z")

</div>

Just another observation: if I remove the pause altogether, then the system hangs. So presumably bind is not used as a possible point at which to schedule another thread.

---

<div class="post-metadata">

**Author:** ![antron](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/antron/32/62_2.png) [@antron](https://discuss.ocaml.org/u/antron)\
**Post date:** [September 20, 2018, 3:07pm UTC](https://discuss.ocaml.org/t/lwt-message-queue-multiple-writer-single-reader/2567/10 "2018-09-20T15:07:32Z")

</div>

@thomas_ridge Lwt’s scheduler doesn’t fully know if you’ve started I/O yet, mainly because _some_ I/O is implemented by running calls in worker threads, and the functions that dispatch work to those threads currently don’t notify the scheduler when work starts. The completions from these I/O calls are communicated on a pipe, and Lwt has to monitor at least that pipe.

Note that you would get bad performance also if you started one very long-running I/O operation in the “background” in your test case, so the issue isn’t about whether Lwt knows there is any I/O completion to check for. It’s about how often it calls `select`/etc. when there is CPU work left (the `Lwt.pause` queue Is not empty), but I/O _happens_ not to be completing for any reason.

> Just another observation: if I remove the pause altogether, then the system hangs. So presumably bind is not used as a possible point at which to schedule another thread.

Indeed. We had an issue about changing that ([Lwt semantic improvements: exception safety and stack overflows by aantron · Pull Request #500 · ocsigen/lwt · GitHub](https://github.com/ocsigen/lwt/pull/500)), but eventually decided not to do it.

To be more precise, if the promise you are calling `bind` on is already resolved, the callback is called right away.

`Lwt.pause` is the only call that introduces pending promises in your test, so removing it makes your program completely synchronous. I think, then, the first writer to run loops forever, or until memory runs out.

And I hope only the program hangs, not your whole system 🙂

---

<div class="post-metadata">

**Author:** ![thomas\_ridge](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/thomas_ridge/32/1478_2.png) [@thomas\_ridge](https://discuss.ocaml.org/u/thomas_ridge)\
**Post date:** [September 21, 2018, 8:13am UTC](https://discuss.ocaml.org/t/lwt-message-queue-multiple-writer-single-reader/2567/11 "2018-09-21T08:13:07Z")

</div>

@antron Thank you very much!
