[MLton] callcc and space use
Matthew Fluet
fluet at tti-c.org
Wed Jan 23 07:21:10 PST 2008
On Wed, 23 Jan 2008, Vesa Karvonen wrote:
> My statement above about the way continuations are implemented is
> somewhat inaccurate. Both threads and continuations are implemented
> on top of primitive threads.
Correct.
> Both callcc and throw copy the primitive
> thread (time proportional to stack size) and then perform a primitive
> thread switch (I assume constant time).
Correct. Both copy current (primitive) thread and copy (primitive) thread
take time proportional to the stack size of the thread. A (primitive)
thread switch is constant time.
> Thread switch does not
> require copying primitive threads, except in the special case of a
> newly created thread.
A primitive thread switch does not require copying primitive threads.
In the MLton.Thread structure, the non-primitive thread switch does copy
a primitive thread when switching to a new non-primitive. And, as noted
by Florian and Vesa, that copy is of a small stack captured at the
beginning of the program, so that operation can reasonably be considered
constant time.
> OTOH, both callcc and throw always copy the stack. So, if you perform
> suspend+resume using callcc+throw, you'll copy the stack twice.
That is true. Because continuations are not one-shot, you need to make a
copy for each throw.
>> However, the function to call is passed to the nascent thread in a
>> global variable (with suitable locking), and this results in unnecessary
>> contention in a parallel environment.
>
> True. OTOH, note that callcc/throw also use the equivalent of a
> global variable. The call to Thread.copyCurrent saves the copy in a
> field in GC state, which is then retrieved by calling Thread.savedPre.
> Both callcc and throw also perform locking (atomicBegin - atomicEnd).
Note that atomicBegin/atomicEnd is very lightweight locking -- they
currently simply inc/dec a global variable. They are only suitable to
prevent switching between ML threads within a single OS thread of control.
> In summary, assuming my understanding of the implementation is
> correct, using callcc+throw to spawn a new thread and perform N
> suspends and resumes takes O((N+1)*S) time, where S is the average
> stack size, while the same with threads takes O(N+1) time.
That sounds about right.
More information about the MLton
mailing list