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 calling
schedule(), 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|virtualinstructionsare 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 theattribute
tasklet.nesting_levelon 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 of
schedule():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 than
schedule(), is tobuild your own yielding primitive without using channels. This is wherethe otherwise ignored optional argumentretval and the return valueare useful.tasklet.tempvalis 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.tempvalbefore 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 theuseful
tasklet.block_trapattribute. 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 of
Nonewill result in thecallback being disabled. The function returns the previous channel callback orNoneif 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 or
Noneif 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 or
Noneif 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 valueof
getcurrent()and the value ofcurrentareimplementation 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 or
Noneif 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 the
switchtraplevel. Returns its previous value.When the
switchtraplevel 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.runcount¶The number of currently runnable tasklets.
Example - usage:
>>>stackless.runcount1
Note
The minimum value of
runcountwill 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 default
pickle_with_tracing_stateisFalse. 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¶
- exception
TaskletExit¶ This exception is used to silently kill a tasklet. It should not becaught by your code, and along with other important exceptions like
SystemExit, be propagated up to the scheduler.The following use of the
exceptclause should be avoided:try:some_function()except:pass
This will catch every exception raised within it, including
TaskletExit. Unless you guarantee you actually raise the exceptionsthat should reach the scheduler, you are better to useexceptin 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 from
BaseException, rather thanException.This class is derived from
SystemExit. It is defind in the modulesexceptionsand__builtin__.
Classes¶
- class
stackless.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)
