9 czerwca 2009

Stackless Python - jak zrobić mikrowątki na localhost

Dziś zapraszam do kilku prób zrobienia z naszego lokalhosta maszyny z działającymi w tle mikrowątkami Stackless Python, które potrafią dość wiele zdziałać. Aby dowiedzieć się jak wiele polecam przeczytanie artykułu o grze EVE on-line, która bazuje na tym rozwiązaniu.

Ważnym wprowadzeniem będzie teoria na wikipedii dotycząca Distributed computing. Są różne podejścia do reazlizacji wielowątkowości i jej synchronizajci. Zasadniczo doceniam w tym artykule specyficzne, bo posiadające w API dosłownie kilka funkcji. Zaimplementowanych w taki sposób, że aż się miło testuje i wdraża takie rozwiązanie. Oczywiście porównuję tutaj API systemowe np: WINAPI i POSIX THREADS. Jest z tym nieco zabawy w projektowaniu i kodowaniu, dlatego przedstawiam Stackless Python, który może rowiązać więcej problemów niż tylko wymienione niewygody wielowątkowości w naszym systemie operacyjnym.

Okazuje się, że programowanie wielowątkowe na większą skalę wcale nie musi posiadać skomplikowanego API. Projektanci Stackless Python doskonale o tym wiedzieli i uprościli bazowe elementy API do następujących pojęć:

  • Tasklets

  • The Scheduler

  • Channels


Zacznę od bazowego przykładu, który pokazuje, jak rozpocząć zabawę z tą technologią. Do wykonania poniższego kodu będzie potrzebna obecność w naszym systemie pypy-stackless.

Tasklets są podstawowym budulcem dla stackless. Możesz utworzyć zadania tasklet przez dodanie zwykle funkcji lub metody klasy. Stworzony w ten sposób tasklet zostaje dodany do harmonogramu zadań. Zauważ, że kolejka taskletów i nie działaja, dopóki nie nastąpi wywołanie metody stackless.run().
Oto prosta demonstracja:
# example1.py

import stackless

def print_x(x):
print x

stackless.tasklet(print_x)('one')
stackless.tasklet(print_x)('two')
stackless.tasklet(print_x)('three')

stackless.run()

Uruchamianie przykładu oraz rezultaty działania:

$ pypy-stackless example1.py
one
two
three

Scheduler kontroluje kolejność, w jakiej tasklets są uruchamiane. Jeśli po prostu stworzysz kilka taskletów, będą uruchamiane w kolejności, w jakiej zostały utworzone. W ogólnej praktyce będzie to związane ze stworzeniem i wywołaniem dodanych taskletów za każdą iteracją ogólnego mechnizmu obiegu danych.
Zauważ, że gdy wywołujemy stackless.schedule(), aktywnym tasklet zatrzymuje się i ponownie wstrzykuje się do końca schedulera w kolejce, pozwalając następnemu taskletowi uruchomić się. Gdy wszystkie z aktywnych taskletów zostaną uruchomione, następuje przywoływanie pozostałych. To trwa do zakończenia wszystkich aktywnych taskletów. W ten sposób osiągamy wielowątkowość we współpracy z stackless.
Szybka demonstracja:

# example2.py

import stackless

def print_three_times(x):
print "1:", x
stackless.schedule()
print "2:", x
stackless.schedule()
print "3:", x
stackless.schedule()

stackless.tasklet(print_three_times)('first')

stackless.tasklet(print_three_times)('second')

stackless.tasklet(print_three_times)('third')

stackless.run()

Uruchamianie przykładu oraz rezultaty działania:

$ pypy-stackless example2.py
1: first
1: second
1: third
2: first
2: second
2: third
3: first
3: second
3: third



Channels czyli kanały umożliwiają wysyłanie informacji między tasklets. To realizuje dwie rzeczy:

Pozwala to na wymianę informacji między tasklets.
Pozwala to na kontrolę przepływu egzekucji.

Kolejna szybka demonstracja:


# example3.py

channel = stackless.channel()

def receiving_tasklet():
print "Recieving tasklet started"
print channel.receive()
print "Receiving tasklet finished"

def sending_tasklet():
print "Sending tasklet started"
channel.send("send from sending_tasklet")
print "sending tasklet finished"

def another_tasklet():
print "Just another tasklet in the scheduler"

Uruchamianie przykładu oraz rezultaty działania:
$ pypy-stackless example3.py



Recieving tasklet started
Sending tasklet started
send from sending_tasklet
Receiving tasklet finished
Just another tasklet in the scheduler
sending tasklet finished


Kilkoma słowami chciałbym podsumować opisane rozwiązanie w Stackless Python. Po pierwsze ilość dostępnych funkcji w API oraz sposób ich użycia szczególnie zachęca do zgłębiania i używania (4 - 6 funkcji). Zarazem niesamowitym osiągnięciem jest fakt, że tak wielki projekt gry on-line jak EVE bazuje na tak prostym i wydajnym rozwiązaniu.

Zachęcam do opisania swoich doświadczeń ze Stackless Python w komentarzach, chętnie podyskutuję.

Mariały dodatkowe:

Stackless Python Homepage

why stackless

Is Stackless Python for You?

Introduction to Concurrent Programming with Stackless Python

Wątki


http://www.archivum.info/pl.comp.lang.python/2008-03/msg00119.html

http://forum.gamedev.pl/index.php?action=printpage%3Btopic=6678.0


Kurs Pisania OS

Debug pamięci w Linuksie (pamięć od strony technicznej)

Dynamiczne zarządzanie pamięcią w C bez wycieków

Stackless Python - artykuly

CORBA Guru Steve Vinoski on REST, Web Services, and Erlang

5 komentarzy:

Anonimowy pisze...

http://entitycrisis.blogspot.com/2009/06/gil-vs-stackless-benchmarks.html

Anonimowy pisze...

http://code.google.com/p/fibra/

Anonimowy pisze...

http://seun-python.blogspot.com/2009/06/gil.html

Anonimowy pisze...

http://entitycrisis.blogspot.com/2009/03/concurrent-scaling-benchmarks.html

Anonimowy pisze...

http://entitycrisis.blogspot.com/2009/03/benchmarking-stackless-kamaelia-and.html