Skip to content

Commit

Permalink
Add post: Lifetime Event Loop
Browse files Browse the repository at this point in the history
  • Loading branch information
straight-shoota committed Nov 14, 2024
1 parent f7f0fc6 commit df02454
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 0 deletions.
2 changes: 2 additions & 0 deletions _data/authors.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,5 @@ alex-kampa:
name: Aleksander Kampa
carlhoerberg:
name: Carl Hörberg
ysbaddaden:
name: Julien Portalier
88 changes: 88 additions & 0 deletions _posts/2024-11-05-lifetime-event-loop.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
---
title: "Lifetime Event Loop"
author: straight-shoota,ysbaddaden
summary: ""
categories: technical
tags: [feature, eventloop, concurrency]
---

A core component of Crystal's concurrency model is the **event loop**. It
integrates asynchronous operations into the runtime, enabling other fibers to
run while one fiber waits to read data on a socket, for example.

We're changing how the event loop operates under the hood on Unix systems.

The new implementation integrates the Crystal event loop directly with system
selectors, [`epoll`](https://linux.die.net/man/7/epoll) (Linux, Android) and
[`kqueue`](https://man.freebsd.org/cgi/man.cgi?kqueue) (BSDs, macOS) instead of
going through [`libevent`](https://libevent.org/).

In the process we're changing that file descriptors now stay subscribed to the
event loop for their entire lifetime, instead of being added and removed on
every single operation. This reduces overhead and improves performance.

This post highlights the relevant information for users.

More technical details are available in [RFC #0009].

## Effects

The new implementation has been merged into `master` and is available in
[nightly builds](/install/nightly).

No changes in user code are required, everything plugs right in.

The new implementation is supported on Linux, macOS, FreeBSD and Android and
automatically enabled on these systems. Read [more about
availability](https://github.com/crystal-lang/rfcs/blob/rfc/lifetime-event_loop/text/0009-lifetime-event_loop.md#availability)
in the RFC.

All other operating systems keep the previous event loop driver: `libevent` on
Unix systems, `IOCP` on Windows.

In case of performance regression or other issues, you can switch
back to the legacy event loop implementation with the compile-time flag
`-Deventloop=libevent`.

Dropping `libevent` removes an external runtime dependency from Crystal
programs.

## Caveats

In some cases the new implementation may cause issues. If you're affected,
we recommend falling back to `libevent` with `-Deventloop=libevent`.

We are aware of some scenarios but believe they are quite rare and should not
hinder general availability of this new feature. Exposure through nightly builds
should help us gather more usage data to assess whether there are any more
noteworthy implications we have not been aware of.

### Timers and Timeouts

At this point, there's a missing optimization for timers (`sleep 1.second`) and
timeouts (`socket.read_timeout = 1.second`). In case you're using lots of them,
it might lead to performance degradation.

This is only a temporary limitation until we finish the implementation of an
efficient data structure. We're already working on that.

### Multi-Threading

The new implementation works well with the multi-threading preview
(`-Dpreview_mt`), having one event loop instance per thread.

There is on caveat though: Moving file descriptors with pending operations
between event loop instances – i.e. between threads – is an error.

For example: Let's assume fiber `A` running on thread `X` waits on file
descriptor `4`. While this operation is still pending, fiber `B` running on
thread `Y` tries to start another operation on file descriptor `4`. This is now
going to raise. File descriptors can only be owned by a single event loop
instance.

This limitation will be mitigated with the arrival of execution contexts from
[RFC #0002] which share one event loop instance between all threads in a
context.

[RFC #0002]: https://github.com/crystal-lang/rfcs/pull/2
[RFC #0009]: https://github.com/crystal-lang/rfcs/pull/9

0 comments on commit df02454

Please sign in to comment.