wiki:Tasklets
Last modified 3 years ago Last modified on 06/05/2012 10:08:00 PM

Tasklets

A tasklet object represents a tiny task in a Python thread. Tasklets are characterized by being very lightweight and portable (SWH: is this true? If so, are all python platforms supported? CT:Yes, see comment below), and make great alternatives to system threads or processes.

At program start, there is always one running main tasklet.

You might also be interested in communicating between tasklets via channels, pickling your tasklets, or other things on the samples page.

Construction

You may construct a tasklet several different ways.

Starting with the following definition:

import stackless

def aCallable(value):
    print "aCallable:", value

you may create a live tasklet inline:

task = stackless.tasklet(aCallable)
task.setup('Inline using setup')
# or task('Inline using ()')

or create a live tasklet using bind():

task = stackless.tasklet()
# some code
task.bind(aCallable)
task.setup('Bind using setup')
# or task('Bind using ()')

deprecated: or in more sophisticated situations, using become() or capture().

After creating the tasklet, you can invoke it using task.run(), stackless.run(), or stackless.schedule().

Scheduling

Scheduling controls switching between tasklets. Until a tasklet is scheduled, it will not be invoked.

Note

If a tasklet is blocked via channels, it will not be invoked by the scheduler until reactivated by that channel.

run()
Schedules this tasklet at the front of the scheduler list, given that it isn't blocked. Blocked tasks need to be reactivated by channels.
kill()
Raises a TaskletExit exception and immediately activates the tasklet. Note that this is a regular xception that can be caught within the tasklet. If the exception passes the toplevel frame of the tasklet, the tasklet will silently die. (As opposed to OS threads, other exceptions are not silent and will show up in the main tasklet).
insert()
Insert this tasklet at the end of the scheduler list, given that it isn't blocked. Blocked tasklets need to be reactivated by channels.
remove()
Removing a tasklet from the runnables queue.

Note

If this tasklet has a non-trivial C stack attached, it will be destructed when the containing thread state is destroyed. Since this will happen in some unpredictabl order, it may cause unwanted side-effects. Therefore it is recommended to either run tasklets to the end or to explicitly kill() them.

scheduled property

A tasklet is said to be scheduled if it is either in the runnables list or waiting in a channel.

This attribute is computed.

blocked property
Nonzero if waiting on a channel (1: send, -1: receive).

Critical Sections

In any MultiTasking environment the ability to atomically execute a section of code is very important. To create a critical section in stackless, use the following idiom:

import stackless

currentTasklet = stackless.getcurrent()
atomic = currentTasklet.set_atomic(True)
try:
    print "Executing critical section"
finally:
    currentTasklet.set_atomic(atomic)

What are the stackless methods? --littldo, Thu, 15 Apr 2004 03:01:36 +0200

Where can I find the stackless methods? CT: use help(stackless)

timers, semaphores? --wware, Thu, 22 Sep 2005 17:12:12 +0200

Back in the microthread days there were timers and semaphores and other RTOS-like paraphenalia. I'm not seeing them any more, were they given up on?

semaphores ... --tomservo291, Wed, 12 Oct 2005 16:07:44 +0200

I believe that semaphores are used primarily with C. They are used to provide a failsafe way to set a single variable to determine who is running in a multi-task enviornment.

The reason they are used is because the OS "owns" the memory the semaphore exists in, and allows only one process/thread to access & change its value at any given time.

If you are able to perform mutual exclusion without semaphores reliably, there is no reason why you should need them to do so; which may be the case here, but I could be mistaken.

tasklet portability --tismer, Fri, 11 Nov 2005 07:44:56 +0100

Hard to explain (needs a new page). tasklets are by nature platform independent. Stackless is not, because it is able to mangle the C stack.

Stackless uses cooperative context switches wherever it can. That means the stack unwinding operations are visible to and supported by the interpreter. This is the most efficient task switching mode possible. In this mode, tasklets are completely OS independent.

There are of course situations where Stackless cannot do cooperative task switching, because the C implementation has certain callbacks which cannot be made stackless by reasonable effort. In this situation, the C stack is captured and attached to the current tasklet, making "a non-trivial C stack", mentioned elsewhere. A tasklet in this state is absolutely OS dependant in the sense that this only works if the OS is supported by Stackless.

It would be possible to produce an OS independent Stackless, this is what Stackless 1.0 did. It would just be much less powerful and fail to switch context in many situations.

Note that these problems have completely vanished in the PyPy project. Here we can produce stackless support code for all situations automatically. But the C stack problems may come back on us when we support calling into third-party code from PyPy.

Mutual exclusion --wware, Mon, 21 Aug 2006 13:36:02 +0200

I can see there are mechanisms for intertask communication and that's good. But you still want a mutual exclusion mechanism for when several tasks want access to a single data structure. In Java, each object gets a lock or monitor, and there is a well-designed mechanism where a thread can claim ownership of the object while it performs some multi-step atomic operation. Are there any locks in Stackless these days? Is the recommendation to use threading.Lock()?

Re: Mutual exclusion --rmtew, Tue, 22 Aug 2006 10:30:04 +0200

We have a set of locking primitives we use at CCP, and while there is an old out of date version of our uthread.py in PCBuild, I will ask permission to modify our latest version to replace the older one.

Re: Mutual exclusion --antony500, Mon, 12 Nov 2007 22:19:01 +0100

"Are there any locks in Stackless these days? Is the recommendation to use threading.Lock()?" - wware

Do we need locks when we have atomic execution? It seems to me the concept behind Stackless is simplicity (leading to programmer efficiency and readability of code). I think I can achieve everything I need by using the atomic mechanism. No need for semaphores, no need for explicitly "locking" objects, etc.

tasklet.kill() / TaskletExit? scope? --eykd, Mon, 14 Jan 2008 17:37:22 +0100

Can anyone explain more clearly how kill() works? TaskletExit seems to be making it to the calling scope, but the documentation suggests (to me, at least) that the TaskletExit exception is supposed to disappear silently along with the killed tasklet.

That is to say, does tasklet.kill() need to be wrapped in a try:...except TaskletExit: block?

Re: tasklet.kill()/TaskletExit? scope? --rmtew, Sat, 23 Feb 2008 19:34:21 +0100

The exception should not make it to the tasklet kill is called from. If you can make a reproduction case, please post it to the mailing list.