[Openmcl-devel] type specifier '(simple-vector n) in defmethod

Nicolas Martyanoff nicolas at n16f.net
Sat Jan 6 06:00:56 PST 2024


"R. Matthew Emerson" <rme at acm.org> writes:
> What do you mean by a “userland thread based runtime”? Does that mean
> that you would prefer cooperatively-scheduled / coroutine style Lisp
> processes (like old MCL had)?
>
> Dealing with preemptively-scheduled OS threads is a pain, but
> multicore processors are extremely common, and it seems important for
> Lisp to be able to make use of them.

CCL processes, the same was as SBCL threads, are directly mapped to OS
threads. OS threads are heavy, you cannot just create millions. So to
deal with concurrent IO operations (my bread and butter), you need
epoll/kqueue[1] and you end up in callback hell where your entire
application is a state machine where every IO operation has to be
non-blocking and you have to be incredibly careful not to block the main
loop (usually delegating work to a thread pool e.g. for disk
operations).

In CL, this really does not map well to streams because streams are
fundamentally blocking (see for example the semantic of READ-SEQUENCE).
I have some experimental code for non-blocking streams [2], but it is
awkward to use and you have to write your parsers very carefully. This
also leads to highly complex multithreaded code (interaction between IO
event handling and workers), and no one is smart enough for that.

The right way, as done in Erlang and more recently Go, is to use green
(userland) threads mapped to multiple OS threads. Each green thread can
be very lightweight (an Erlang process starts with less than 2kB of
heap), start almost instantly and you can spawn millions of them. The
runtime handles scheduling; usually you yield on IO operations and
every N operations ("reductions" in Erlang) otherwise.

This means that you can just spawn one green threads per network
connection (or per concurrent operation, really), write your code the
same way as if it was a non-concurrent program and communicate using CSP
as in Go. In CL, this means one could use streams with the exact same
semantics while the underlying concurrent runtime would handle IO events
correctly.

Useless to say that modifying an existing compiler to switch to this
model is a huge endeavour, which is why I'm saying that if I were to try
this, I would write an implementation from scratch.


[1] Not just to keep memory usage low, but because an idle network
connection blocks its thread potentially forever. Impossible to expose a
server with this risk.

[2] https://github.com/galdor/tungsten/blob/master/tungsten-system/src/tcp-stream.lisp

-- 
Nicolas Martyanoff
https://n16f.net
nicolas at n16f.net


More information about the Openmcl-devel mailing list