Mon Nov 13 09:11:50 EST 2017
What I see mostly is the mixing of state machines. I spend a lot of
time transferring bytes from one buffer to the other, where the
"chunking" is the cause of context switching.
It seems this cannot really be avoided.
However, the core problem in the implementation is where the loops
will be: on the read end or on the write end? It is largely arbitrary
for the meaning of the program, but it makes a lot of difference for
the efficiency, because context switches are not free.
How to make this core problem explicit?
The purpose of an operating system is to connect I/O between multiple
tasks that have individual run state -- either an explicit finite
state machine, or a (finite) stack.
- tasks are exposed as state machines that produce inidividual bytes
through a tick() function.
- efficiency comes from unrolling the state machine tick() functions.
user should only specify buffer sizes and all the rest should be
- source transformation converts any kind of iterator specification
(fold, source, sink, lazy list) into state machines.
So the compile time loop inlining is an essential element.
The key thing to understand here is that the USER INTERFACE is to
write state machines in terms of nested loops. In practice, most
state machens follow that approach. When you actually need a raw
dispatcher and explicit state switcher, it's probably worth it to
implement that in terms of the task abstraction, instead of the other
way around. A source transformation should be able to do this.
Basically, straight-through code with i/o is Erlang, and this is a
really neat model to work with, as it allows effects and purity to be
See also next one.