Skip to content

Commit c70da9a

Browse files
committed
Update README
1 parent 2a5286d commit c70da9a

File tree

1 file changed

+42
-1
lines changed

1 file changed

+42
-1
lines changed

Diff for: README.md

+42-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ modern Linux machines. UringMachine provides a rich API for performing I/O using
2222
- High performance (needs to be proved).
2323
- (Eventually) I/O class with buffered reads and an intuitive API.
2424

25-
## Prior art
25+
## Design
2626

2727
UringMachine is based on my experience marrying Ruby and io_uring:
2828

@@ -32,6 +32,47 @@ UringMachine is based on my experience marrying Ruby and io_uring:
3232
- [IOU](https://github.com/digital-fabric/iou) - a low-level asynchronous API
3333
for using io_uring from Ruby.
3434

35+
Some important learnings from those two projects, in no particular order:
36+
37+
- Monkey-patching is not a good solution, long term. You need to deal with
38+
changing APIs (Ruby is evolving quite rapidly these days!), and anyways you're
39+
always going to get stuck with some standard Ruby API that's implemented as a
40+
C extension and just won't play nice with whatever you're trying to do.
41+
- The design of the Polyphony io_uring backend was an evolution of something
42+
that was originally based on libev as an event loop. In hindsight, adapting
43+
the design for how io_uring worked led to code that was too complex and even
44+
somewhat brittle.
45+
- IOU showed me that even if we embrace callbacks, the developer experience is
46+
substantially inferior to what you can do with a sequential coding style. Even
47+
just in terms of line count - with callbacks you end up with roughly double
48+
the number of lines of code.
49+
- Implementing fiber switching on top of IOU was disappointing in terms of
50+
performance. In order for a fiber-based solution to be performed it had to be
51+
baked in - hence UringMachine.
52+
- Working with fibers has the very important benefit that you can keep stuff on
53+
the stack, instead of passing around all kinds of references to the heap. In
54+
addition, you mostly don't need to worry about marking Ruby objects used in
55+
operations, since normally they'll already be on the stack as method call
56+
parameters.
57+
- Polyphony was designed as an all-in-one solution that did everything: turning
58+
stock APIs into fiber-aware ones, providing a solid structured-concurrency
59+
implementation for controlling fiber life times, extensions providing
60+
additional features such as compressing streaming data between two fds, other
61+
APIs based on splicing etc. Perhaps a more cautious approach would be better.
62+
- Pending operation lifetime management in Polyphony was based a complex
63+
reference counting scheme that proved problematic, especially for multishot
64+
operations.
65+
66+
So, based on those two projects, I wanted to design a Ruby API for io_uring
67+
based on the following principles:
68+
69+
- Automatic fiber switching.
70+
- No monkey-patching. Instead, provide a simple custom API, as a replacement for
71+
the stock Ruby `IO` and `Socket` classes.
72+
- Simpler management of pending operation lifetime.
73+
- Do not insist on structured concurrency, just provide the APIs necessary to
74+
create actors and to supervise the execution of fibers.
75+
3576
## Example
3677

3778
```ruby

0 commit comments

Comments
 (0)