I'm coming into this late and with only a partial comment, but another approach is coroutines (a special case of continuations). Coroutines feel like threads but are non-preemptive like events. Python generators are themselves a special case of coroutines and Stackless Python has [had?] coroutines and continuations (although theirs seems a little more obtuse than I think it should be).
As an example application, SimPy uses generators in a "coroutine like" fashion for creating dozens or hundreds of "threads of execution". The code for the each "thread" is straightforward and linear, normal Python methods.