Friday, 6 June 2008

Stackless notes #1

Creating a tasklet

When you create a tasklet, it is automatically scheduled. This places it at the end of the list of scheduled tasklets, and out of all the tasklets currently waiting to run, it will get its turn last.

Scheduling a new tasklet:

>>> def f():
... pass
...
>>> stackless.tasklet(f)()
There is no need to hold a reference to the tasklet to keep it alive. The scheduler holds a reference to all scheduled tasklets.

Binding a callable to a tasklet:
>>> def f(arg, kwarg=None):
... pass
...
>>> t = stackless.tasklet(f)
>>> t.scheduled
False
>>> t.alive
False
Supplying the parameters for the callable:
>>> t = stackless.tasklet(f)
>>> t(1, kwarg=2)
<stackless.tasklet object="" at="" 0x01b031b0="">
>>> t.alive
True
>>> t.scheduled
True
Running the scheduler

Once started, it will continue to run until it has no scheduled tasklets remaining.
>>> def f():
... print "scheduled once"
... stackless.schedule()
... print "scheduled twice"
...
>>> stackless.tasklet(f)()
<stackless.tasklet object at 0x01B03170>
>>> stackless.run()
scheduled once
scheduled twice
>>>
If a tasklet never exits, the scheduler will continue to run forever. This would happen with the following function:
>>> def f():
... while True:
... stackless.schedule()
...
>>>
Running the scheduler normally

As already shown, the normal way to use Stackless Python, is to create your tasklets and then to run the scheduler until they have all either blocked out of it, or run to completion.

An example function to schedule as a tasklet:
def SomeFunction():
while not shouldExit:
# Do whatever it is this tasklet is supposed to do.
pass
# We need to yield to allow the other scheduled tasklets to run.
stackless.schedule()
Create and schedule the tasklet:
stackless.tasklet(SomeFunction)()
Run the scheduler until there are no remaining scheduled tasklets:
stackless.run()
Using this approach, Stackless is a framework and it drives the running of your application. If your application needs to do something, then it needs to create a tasklet to run alongside the others in the scheduler.

Running the scheduler in a more flexible way

It is often less constraining not to have to shape your program to fit inside a framework. This is not how Stackless was used above, in the normal manner. But it can be done by approaching things a little bit differently.

This is what we do in EVE Online, as Kristján Valur Jónsson described in his presentation at PyCon 2006. The approach is described in the Stackless Python idioms wiki page, as the 'Being Nice' idiom.

In a nutshell, rather than yielding your tasklets to the end of the scheduled tasklet list, you yield them onto a channel and out of the scheduler. This is the 'BeNice' function:
def LoopingFunction():
BeNice()
The scheduler will then exit after each tasklet has been run once. Then when you next get to the point when you can run the scheduler again, you first wake up each tasklet on your yield channel, then run the scheduler.
def MainLoop():
while not exit:
RunNiceTasklets()
stackless.run()
The Stackless 'schedule' method should not be used to yield any more, otherwise you will block on the scheduler running until the tasklets which use it are blocked off the scheduler in some other way, or have exited.

An example implementation of this is provided in the uthread module.
import uthread

def LoopingFunction():
uthread.BeNice()

if __name__ == "__main__":
uthread.Run()
Of course, as is, it is not much use. You need to integrate your logic into the loop within your own version of the 'Run' function. Otherwise, you are not much better off than just using Stackless normally.

Thursday, 5 June 2008

PyCon 2006 / Stackless Python presentation video

Back in 2006, CCP attended its first PyCon. Kristján Valur Jónsson and I were sent to attend, with Kristján Valur doing a presentation and both of us sprinting to bring Stackless Python up to date. Christian Tismer had been preoccupied with PyPy. But he kindly made himself available to hold our hands through the sprint.

On a whim I acquired CCP's video camera and recorded Kristján Valur's presentation. However, the tape was never processed and sat in and on various desks for over a year. Since I am leaving CCP, I decided to make sure this video was processed.


However this wasn't an easy matter. The video was extracted from the tape into an avi file encoded with a Sony DV codec. Nothing except for Microsoft tools seemed to want to recognise the audio. Which meant that if I wanted to encode an XviD version, I needed to reencode an existing WMV reencoding of the Sony DV avi. Unfortunately this was a dead end, no matter what I tried I was unable to get the XviD to have audio which was in sync with the video. The WMV played perfectly of course. Windows Media Encoder was a pleasure to use - it just worked. I tried using AutoGK and StaxRip for the XviD encoding and they were also a pleasure to use, but just weren't able to do the job.

If anyone can convince me that they have experience working around audio sync problems and converting Sony DV codecs, I can provide the 8 GB Sony DV avi or the 1 GB WMV for reencoding to XviD.

Anyway, here is the video on Google Video:



Originally posted 2007/30/05; Updated 2008/06/05: Reuploaded the video, which was not working. Previously, it would upload and sit in the Processing state. I gave up and left it that way for a year. Reuploading it now, Google seem to have updated their quality to blurry converter to be able to handle the WMV format better.

Wednesday, 4 June 2008

mudconnect.com: Python MUD codebases

Link: Calling all Python muds

Idealiad:

Inspired lately by Python I wrote up a short list of all the Python muds I could find. Note that I couldn't get working links for some sources so I left those out. If your Python mud isn't included here would you add it?

Here's what I have so far:
...
The thread gathers together links to 17 different Python MUD codebases.