stackless — The built-in extension module

New in version 1.5.2.

Thestackless module is the way in which programmers must accessthe enhanced functionality provided byStackless-Python.

Functions

The main scheduling related functions:

stackless.run(timeout=0,threadblock=False,soft=False,ignore_nesting=False,totaltimeout=False)

When run without arguments, scheduling is cooperative.It us up to you to ensure your tasklets yield, perhaps by callingschedule(), giving other tasklets a turn to run. The schedulerwill exit when there are no longer any runnable tasklets left within it.This might be because all the tasklets have exited, whether by completingor erroring, but it also might be because some are blocked on channels.You should not assume that whenrun() exits, your tasklets haveall run to completion, unless you know for sure that is how youstructured your application.

The optional argumenttimeout is primarily used to run the schedulerin a different manner, providing pre-emptive scheduling. A non-zerovalue indicates that as each tasklet is given a chance to run, itshould only be allowed to run as long as the number of|PY|virtualinstructions are below this value. If atasklet hits this limit, then it is interrupted and the schedulerexits returning the now no longer scheduled tasklet to the caller.

Example - run until 1000 opcodes have been executed:

interrupted_tasklet=stackless.run(1000)# interrupted_tasklet is no longer scheduled, reschedule it.interrupted_tasklet.insert()# Now run your custom logic....

The optional argumentthreadblock affects the way Stackless works whenchannels are used for communication between threads. Normally whenthe scheduler has no remaining tasklets to run besides the current one,the main tasklet is reawakened. By engaging this option, if there are otherrunningPython® threads then the current one will instead block expectingthem to eventually wake it up.

The optional argumentsoft affects how pre-emptive scheduling behaves.When a pre-emptive interruption would normally occur, instead ofinterrupting and returning the running tasklet, the scheduler exits atthe next convenient scheduling moment.

The optional argumentignore_nesting affects the behaviour of theattributetasklet.nesting_level on individual tasklets. If set,interrupts are allowed at any interpreter nesting level, causing thetasklet-level attribute to be ignored.

The optional argumenttotaltimeout affects how pre-emptive schedulingbehaves. Normally the scheduler is interrupted when any giventasklet has been running fortimeout instructions. If a value isgiven fortotaltimeout, instead the scheduler is interrupted when ithas run fortotaltimeout instructions.

This function can be called from any tasklet. When called withoutarguments, the calls nest so that the innermost call will returnonce the run-queue is emptied. Calls with atimeout argumenthowever stack so that only the first one has any effect. Subsequentcalls withtimeout behave as though timeout were omitted. This allowsa stackless application to be monitored on the outside without theinner application modifying the outer behaviour.

Note

The most common use of this function is to call it either withoutarguments, or with a value fortimeout.

stackless.schedule(retval=stackless.current)

Yield execution of the currently running tasklet. When called, the taskletis blocked and moved to the end of the chain of runnable tasklets. Thenext tasklet in the chain is executed next.

If your application employs cooperative scheduling and you do not usecustom yielding mechanisms built around channels, you will most likelycall this in your tasklets.

Example - typical usage ofschedule():

stackless.schedule()

As illustrated in the example, the typical use of this function ignoresboth the optional argumentretval and the return value. Note that asthe variable nameretval hints, the return value is the value of theoptional argument.

stackless.schedule_remove(retval=stackless.current)

Yield execution of the currently running tasklet. When called, thetasklet is blocked and removed from the chain of runnable tasklets. Thetasklet following calling tasklet in the chain is executed next.

The most likely reason to use this, rather thanschedule(), is tobuild your own yielding primitive without using channels. This is wherethe otherwise ignored optional argumentretval and the return valueare useful.

tasklet.tempval is used to store the value to be returned, andas expected, when this function is called it is set toretval. Customutility functions can take advantage of this and set a new value fortasklet.tempval before reinserting the tasklet back into thescheduler.

Example - a utility function:

defwait_for_result():waiting_tasklets.append(stackless.current)returnstackless.schedule_remove()defevent_callback(result):fortaskletinwaiting_tasklets:tasklet.tempval=resulttasklet.insert()waiting_tasklets=[]deftasklet_function():result=wait_for_result()print("received result",result)

One drawback of this approach over channels, is that it bypasses theusefultasklet.block_trap attribute. The ability to guard againsta tasklet being blocked on a channel, is in practice a useful ability tohave.

Callback related functions:

stackless.set_channel_callback(callable)

Install a global channel callback. Every send or receive action will resultincallable being called. Setting a value ofNone will result in thecallback being disabled. The function returns the previous channel callback orNone if none was installed.

Example - installing a callback:

defchannel_cb(channel,tasklet,sending,willblock):passstackless.set_channel_callback(channel_cb)

Thechannel callback argument is the channel on which the action isbeing performed.

Thetasklet callback argument is the tasklet that is performing theaction onchannel.

Thesending callback argument is an integer, a non-zero value of whichindicates that the channel action is a send rather than a receive.

Thewillblock callback argument is an integer, a non-zero value of whichindicates that the channel action will result intasklet being blockedonchannel.

stackless.get_channel_callback()

Get the current global channel callback. The function returns thecurrent channel callback orNone if none was installed.

stackless.set_schedule_callback(callable)

Install a callback for scheduling. Every scheduling event, whetherexplicit or implicit, will result incallable being called. The functionreturns the previous channel callback orNone if none was installed.

Example - installing a callback:

defschedule_cb(prev,next):passstackless.set_schedule_callback(callable)

Theprev callback argument is the tasklet that was just running.

Thenext callback argument is the tasklet that is going to run now.

Note

During the execution of the scheduler callback the return valueofgetcurrent() and the value ofcurrent areimplementation defined. You are not allowed to execute any methods, thatchange the state of stackless for the current thread.

stackless.get_schedule_callback()

Get the current global schedule callback. The function returns thecurrent schedule callback orNone if none was installed.

Scheduler state introspection related functions:

stackless.get_thread_info(thread_id)

Return a tuple containing the threads main tasklet, current tasklet andrun-count.

Example:

main_tasklet,current_tasklet,runcount=get_thread_info(thread_id)
stackless.getcurrent()

Return the currently executing tasklet of this thread.

stackless.getmain()

Return the main tasklet of this thread.

stackless.getruncount()

Return the number of currently runnable tasklets.

stackless.switch_trap(change)

modify theswitchtrap level. Returns its previous value.

When theswitchtrap level is non-zero, any tasklet switching,e.g. due channel action or explicit, will result in aRuntimeErrorbeing raised. This can be useful to demark code areas that are supposedto run without switching, e.g.:

stackless.switch_trap(1)# increase the trap leveltry:my_function_that_shouldnt_switch()finally:stackless.switch_trap(-1)

Debugging related functions:

stackless.enable_softswitch(flag)

Control the switching behaviour.Tasklets can be either switched by moving C stack slices aroundor by avoiding stack changes at all. The latter is only possiblein the top interpreter level. This flag exists once for the whole process.For inquiry only, use ‘None’ as the flag.By default, soft switching is enabled.

Example - safely disabling soft switching:

old_value=stackless.enable_softswitch(False)# Logic executed without soft switching.enable_softswitch(old_value)

Note

Disabling soft switching in this manner is exposed for timing anddebugging purposes.

Attributes

Rather unusually, the module containsattributes for convenient access to somemethods. Since this is not general practice and involves some hacks to attain,please consider this deprecated. Use the corresponding module functions instead.
stackless.current

The currently executing tasklet of this thread.Equivalent function:getcurrent().

stackless.main

The main tasklet of this thread.Equivalent function:getmain().

stackless.runcount

The number of currently runnable tasklets.

Example - usage:

>>>stackless.runcount1

Note

The minimum value ofruncount will be1, as the callingtasklet will be included.

Equivalent function:getruncount().

stackless.threads

A list of all thread ids, starting with the id of the main thread.

Example - usage:

>>>stackless.threads[5148]
stackless.pickle_with_tracing_state

A boolean value, that indicates if a pickled tasklet containsinformation about the tracing and/or profiling state of the tasklet.By defaultpickle_with_tracing_state isFalse. Usuallythere’s no need to change this value.

If you need to set this attribute on a per thread base,you can redefine the attribute as a thread local property:

>>>importstackless>>>importthreading>>>stackless._pickle_with_tracing=threading.local()>>>stackless.__class__.pickle_with_tracing= \...property(fget=lambdam:getattr(m._pickle_with_tracing,'v',False),...fset=lambdam,v:setattr(m._pickle_with_tracing,'v',v),...doc="thread local pickle_with_tracing flag")

Exceptions

exceptionTaskletExit

This exception is used to silently kill a tasklet. It should not becaught by your code, and along with other important exceptions likeSystemExit, be propagated up to the scheduler.

The following use of theexcept clause should be avoided:

try:some_function()except:pass

This will catch every exception raised within it, includingTaskletExit. Unless you guarantee you actually raise the exceptionsthat should reach the scheduler, you are better to useexcept in thefollowing manner:

try:some_function()exceptException:pass

Here only the more common exceptions are caught, as the ones that shouldnot be caught and discarded inherit fromBaseException, rather thanException.

This class is derived fromSystemExit. It is defind in the modulesexceptions and__builtin__.

Classes

classstackless.atomic

This is a context manager class to help with setting up atomic sections.

Use it like this:

withstackless.atomic():sensitive_function()other_sensitive_function()

Its definition is equivalent to the following, only faster:

@contextlib.contextmanagerdefatomic():old=stackless.getcurrent().set_atomic(True)try:yieldfinally:stackless.getcurrent().set_atomic(old)