Erlang style processes in Common Lisp

shenanigans at sonic.net shenanigans at sonic.net
Wed Aug 19 03:24:01 UTC 2015


On 08/17/2015 11:09 PM, Daniel Kochmański wrote:
>> Extending ECL or as a implementation-specific package for it might be
>> >another option, but again, this is beyond my knowledge of its
>> >internals.
> Could you elaborate a little on this?

As a conceptual design without having examined ECL internal docs or 
source-- a very big disclaimer, indeed-- this is one approach 
considering primarily the C & Unix perspective:

1. Since my criteria revolve around cheap & efficient workers and 
cheating garbage collection upon worker exit, I'd build the memory 
management system upon mmap() and munmap() for each worker heap.  All 
memory consed within context of the worker must be constrained to exist 
only within the large blocks of memory from its private mmap()'d areas.

2. Regardless of ECL or other Lisp system, introduce a form such as 
WITH-WORKER that could combine Erlang's spawn() parameters and BODY that 
is maintained as a list for which the form at runtime would time-slice 
between its elements.  WITH-WORKER could vaguely resemble 
WITH-OPEN-FILE, so let's leave it at that for now.  More below.

3. Where Erlang/BEAM has the concept of "reductions" as the means by 
which to introduce and enforce some notion of fairness across workers, 
perhaps the Lispy version *doesn't* try to protect the programmer from 
hurting him/herself.  Iterating over the BODY as list would translate 
into round-robin interleaving across all WITH-WORKER instances on the 
same CPU core-- same scheduler.

4. As with Erlang/BEAM: introduce one scheduler per CPU core. Worker 
migration to re-balance load per core is a pain point, but avoid 
anything too fancy here.  Start with random-but-even distribution and 
random-but-even re-balancing.

(But beware: attempting to localize workers based upon message-passing 
communication patterns adds too much complexity to get correct for the 
"average" use case.  Instead, similarly to thread "colours", just 
specify affinity hints as optional parameters to WITH-WORKER, which 
should be *ignored* on first cut.)

5. As with Erlang/BEAM: when sending messages across cores, *copy* 
rather than share data for better cache locality.  Of course, the Lispy 
approach would probably be to allow copying *or* sharing, and a thin 
package on top of something like SBCL's sb-concurrently (with an 
optional parameter to override) could enforce the recommended approach. 
Caveat below.

(See http://sbcl.org/manual/index.html#sb_002dconcurrency and 
particularly take note of the Edya Ladan-Mozes and Nir Shavit paper 
reference for minimizing locks for queues.)

6. There are obvious points that I've ignored here, such as in order to 
have cheap worker cleanup upon exit, the system would need guarantees 
that no other worker is sharing its data.  There are sound reasons why 
Erlang semantics are pure functional programming! But for the Lispy 
approach, perhaps keep the global heap for such things, and anything to 
be shared goes there-- along with the performance penalty for reaching 
across NUMA nodes.  That is, "here's enough rope..."  But seriously, 
just as Scala used OO early in its lifetime yet largely considers it 
best to avoid that now, so too I suspect we'd feel the same about shared 
read/write memory in the long-run once we have enough lines of code 
written with this proposed system.


Of course, the above may have no contact with reality of ECL.

For instance, if there is an equivalent to a global lock then the above 
design fails quickly.

Perhaps this gives ideas to someone who has working knowledge of such 
internals.

Thanks,
-Daniel




More information about the pro mailing list