0

Podwójne przyspieszenie

Posted by M on 00:16 in ,
Ostatnio w jednym projekcie zajmuje się ujednoliceniem sposobu generowania odpowiedzi w formacie XML. W większości miejsc używany już był lxml, jednak w pewnych miejscach wykorzystane były szablony Django. Największy dokument przed wygenerowaniem miał blisko 600 linii po ładnym sformatowaniu, a i tak zawierał miejsca na podstawienie dodatkowych wstawek XML.
Szablon zawierał także sporą dawkę instrukcji warunkowych i kilka pętli.

W końcu udało się go przepisać, choć finalne rozwiązanie wymagało trochę pracy. Początkowo używane były funkcje Element i SubElement. Pisania było przy tym sporo.

user = Element('user', uid=str(user.id)) # rzutowanie do typu znakowego
login = SubElement(user, 'login')
login.text = user.username # przypisanie do zmiennej, tylko zeby text ustawić
nick = SubElement(user, 'nick')
nick.text = profile.nick
if data.get('options'):
    options = SubElement(user, 'options')
    for k,v in data['options'].items():
        SubElement(options, 'option', key=k, value=v or '') # z None też sobie nie radzi

Kolejnym etapem przemian było zrobienie aliasów E i SE do pełnych nazw funkcji budujących obiekty. To jednak było wciąż zbyt małe usprawnienie. Mając przed sobą jeszcze pewnie ponad 500 linii do przerobienia pojawił się pomysł zrobienia wrappera, lub jak kto woli DSLa.
Jak już całkowicie własną otoczkę robić, to niech eliminuje to co spowalnia pracę.
Jedną z pierwszych funkcji było automatyczne rzutowanie typów liczbowych na typ znakowy - zawsze to 5 znaków mniej do napisania (lxml sam tego nie robił). Kolejną rzeczą była obsługa wartości None - zamiana na pusty ciąg znaków. Poza obsługą różnych typów parametrów mile widziane było wyeliminowanie konieczności przypisywania elementu do zmiennej, aby dodać mu jakiś tekst.
Tutaj pojawiła się propozycja stworzenia metody add, która może przyjąć tekst, jak i inny element.
Po tych zmianach było już łatwiej, ale nadal trzeba było rozbijać na drobne kawałki ze względu na różne instrukcje warunkowe czy pętle.
Ułatwić to miały kolejne dwie metody add_if(condition, *nodes) oraz add_for(iterable, callback).
Dzięki temu możliwe było zapisanie w spójny sposób chyba wszystkich występujących w projekcie przypadków. Poniżej jest odpowiednik przedstawionego wczesniej kodu.

user = E('user', uid=user.id).add(
           E('login').add(user.username),
           E('nick').add(profile.nick),
       ).add_if(data.get('options'),
           E('options').add_for(data.get('options',{}).items(),
               lambda item: E('option', key=item[0], value=item[1])
           )
       )

Praktycznie wszystkie spowalniacze zostały wyeliminowane, a i czytelność na tym zyskała. Pamiętać należy jednak o tym, że w instrukcji warunkowej wszystko jest wykonywane niezależnie od podanego warunku. On służy jedynie do określenia czy dodać utworzone węzły. Jeśli mamy w zależności od warunku pobrać różne dane, nadal lepiej rozbić generowanie XMLa na mniejsze fragmenty kodu i wykorzystać normalną instrukcję if.

Zainteresowanych tym dodatkiem odsyłam do repozytorium.

Po zaimplementowaniu generowania całego długiego dokumentu, z wykorzystaniem przedstawionego wyżej wspomagacza i biblioteki lxml, przyszedł czas na porównanie wydajności. Użyty został jeden serwer testowy, na którym porównane zostały czasy generowania odpowiedzi w stary i nowy sposób.

Testy z użyciem siege, pokazały spadek czasu generowania całej odpowiedzi (łącznie z dostępem do baz danych, cache, etc) z 0.53 sekundy, w przypadku ładowania i parsowania szablonu przez Django, do 0.32 sekundy. Dzięki powyższym zabiegom przyspieszeniu uległo nie tylko pisanie kodu generującego dokument XML, ale także sam czas przygotowywania odpowiedzi dla klienta. Teraz dzieje się to około 1.6x szybciej, co niewątpliwie jest miłym zaskoczeniem.

Żeby nie było tak optymistycznie, napiszę, że nie było użyte cache'owanie szablonów wprowadzone w Django 1.2. Poza tym, istnieją szybsze systemy szablonów, których można użyć razem z wykorzystywaną u nas ramówką. Pewne jest, że w obydwu przypadkach, zysk ze zrezygnowania z szablonu będzie mniejszy, choć w przypadku cache w nowej wersji Django różnica ta pewnie będzie znikoma. Wynika to z faktu, że w tym konkretnym przypadku szablon jest znajdowany i tak w pierwszej próbie (zainteresowanych cache szablonów odsyłam do Django Advent).

0

MacRuby

Posted by M on 02:30 in
MacRuby jest implementacją języka Ruby przeniesioną na platformę Mac OS X i umożliwiającą wykorzystanie wszelkich dobrodziejstw Objective-C. Nie należy jednak mylić tego z mostem, pomiędzy obydwoma językami, jakim jest RubyCocoa. Najnowsza wersja - połóweczka - wykorzystuje LLVM (Low-Level Virtual Machine), zamiast YARV, dzięki czemu zyskała na szybkości. Do kompletu dostajemy także HotCocoa - cienką warstwę, która potrafi usprawnić i przyspieszyć tworzenie aplikacji korzystających z API Cocoa. I jako ostatni bonus, wsparcie, dla wprowadzonego w śnieżnym kociaku, Grand Central Dispatch.

require 'rubygems'
require 'hotcocoa'
include HotCocoa
application do |app|
  win = window :size => [100,50]
  b = button :title => 'Hello'
  b.on_action { puts 'World!' }
  win << b
end

Patrząc na powyższy przykład jedno nasuwa się na myśl - krócej napisać aplikację okienkową na maka będzie ciężko. Po kilku godzinach okazuje się jednak, że zrobienie większości rzeczy wymagać będzie i tak mozolnego grzebania w dokumentacji Cocoa i używaniu wszystkich klas bez pośrednictwa HotCocoa. Wystarczy szybki rzut oka na status by się przekonać jak wiele zostało jeszcze do zrobienia.

Odnośnie samego sposobu tworzenia aplikacji, istnieją dwie drogi - Ruby-way i ObjC-way. Ta pierwsza wykorzystuje HotCocoa, druga skłania się ku użyciu samego MacRuby i będzie bliższa dla miłośników XCode :) Znajdziemy w nim odpowiedni szablon aplikacji, który wygeneruje nam na dzień dobry plik main.m:

#import 

int main(int argc, char *argv[])
{
    return macruby_main("rb_main.rb", argc, argv);
}

a także rb_main.rb, którego zadaniem jest załadowanie wszystkich plików Ruby'ego w projekcie.
Wszystko się tu wyklikuje, przeciąga, używa edytora GUI,  upuszcza, przygotowuje targety, linkuje frameworki. Napewno dobre dla ludzi mających już doświadczenie z C i XCode.

Dla tych, którym bliżej jednak do języków skryptowych, przyjaźniejsza może okazać się pierwsza droga z wykorzystaniem HotCocoa, ulubionego edytora i wiersza poleceń. Nowego projektu się nie wyklikuje, a tworzy poleceniem:

hotcocoa demo

w efekcie czego otrzymamy katalog, a w nim:


Teraz wystarczy z wiersza poleceń wykonać komendę:

macrake build run

i cieszyć się pierwszą aplikacją.
Gdy fascynacja automatycznie wygenerowanym "Hello from HotCocoa" minie i zaczniemy grzebać w kodzie prędzej czy później okaże się, że aplikacja się nie uruchamia prawidłowo. Jest coś co może trochę pomóc:

macruby lib/application.rb --debug

Na tym etapie, zaleca się unikanie sprawdzania ile miejsca zajmuje nasz katalog demo.app :) Dla tych, którzy jednak to zrobią jest światełko w tunelu.

Wpomniałem wcześniej o ilości rzeczy, których brakuje wciąż w HotCocoa. Drobną pomocą są mapowania, dzięki którym możemy dodać własne wsparcie dla rozmaitych fragmentów Cocoa. Niestety na opiekunów projektu nie ma zbytnio co liczyć, gdyż niektóre tickety z gotowym rozwiązaniem czekają miesiącami.

Na koniec garść linków:

* Ruby Manor 2009: Ruby & Cocoa
* Test Driven Development in Objective-C with MacRuby
* Developing Cocoa Applications Using MacRuby
* Heating up with HotCocoa
* Controlling iTunes with MacRuby

0

Przenosiny płatków

Posted by M on 13:01
Przeniosłem mój plugin bazaarowy odpalający pyflakes na githuba.

Niestety bzr co lp:bzr-flakes będzie instalować starą wersję, ale launchpad jest zbyt chaotyczny.
Wersja dostępna w nowym miejscu działa poprawnie z "nowszymi" wersjami Bazaara. Dawno temu, jak żyły jeszcze dinozaury, można było inaczej podpinać się pod akcje wykonywane przed commitem.

0

Comet is dead...

Posted by M on 20:30 in
Porcja linków:
* Brain Dump of Real Time Web(RTW) and WebSocket
* Websockets and Ruby EventMachine
* Websocket Chat
* Ruby & WebSockets: TCP for the Browser
* WebSocket is neither Web nor Socket
Comet is dead long live websockets

Na koniec małe demo do pobrania.

Copyright © 2009 tech.matee.net All rights reserved. Theme by Laptop Geek. | Bloggerized by FalconHive.