<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/css" href="/stylesheets/rss.css"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/">
  <channel>
    <title>Jaros&#322;aw Zabie&#322;&#322;o - BLOG: Tag ruby</title>
    <link>http://blog.zabiello.com/articles/tag/ruby</link>
    <language>en-us</language>
    <ttl>40</ttl>
    <description>moje notatki, linki, komentarze</description>
    <item>
      <title>Merb 0.9.7</title>
      <description>&lt;p&gt;&lt;a href="http://blog.zabiello.com/articles/2008/09/11/merb-0-9-6"&gt;Ostatni wpis&lt;/a&gt; o Merbie 0.9.6 wywo&#322;a&#322; troch&#281; nerwowych reakcji w komentarzach. Niekt&#243;rzy mieli problemy z instalacj&#261; gem&#243;w. M.in. zapl&#261;ta&#322;a si&#281;  liter&#243;wka w pluginie generuj&#261;cym modele &lt;a href="http://sequel.rubyforge.org/"&gt;Sequela&lt;/a&gt;. Wys&#322;a&#322;em &lt;a href="http://merb.lighthouseapp.com/projects/7588/tickets/166-patch-fixed-broken-sequel-generator"&gt;patch&lt;/a&gt;, kt&#243;ry zosta&#322;&#160;ju&#380; wci&#261;gni&#281;ty do repozytorium.&lt;/p&gt;


	&lt;p&gt;Aktualnie oficjalnym gemem Merba dost&#281;pnym ju&#380; w RubyForge jest wersja 0.9.7. Wersja rozwojowa nosi numer 0.9.8. Skr&#243;cono czas wyda&#324; kolejnych gem&#243;w do 5 dni. Gemy z Merbem 0.9.8 maj&#261; wyj&#347;&#263; ok. 20 wrze&#347;nia. Pi&#281;&#263; dni p&#243;&#378;niej, 27 wrze&#347;nia ma pojawi&#263; si&#281; wersja 0.9.9. Ta wersja b&#281;dzie  mia&#322;a zamro&#380;one ca&#322;e &lt;span class="caps"&gt;API&lt;/span&gt; i do wersji 1.0 b&#281;d&#261; ju&#380; tylko poprawiane ewentualne b&#322;&#281;dy. Wersja 1.0 ma wyj&#347;&#263; 11-12 pa&#378;dziernika.&lt;/p&gt;


	&lt;p&gt;Warto zwr&#243;ci&#263; uwag&#281; na gem &lt;a href="http://yehudakatz.com/2008/05/12/by-thors-hammer/"&gt;Thor&lt;/a&gt; b&#281;d&#261;cy ulepszon&#261; kombinacj&#261; &lt;a href="http://rake.rubyforge.org/"&gt;Rake&lt;/a&gt; i &lt;a href="http://errtheblog.com/posts/60-sake-bomb"&gt;Sake&lt;/a&gt;. Pocz&#261;wszy od Merba 0.9.7 &lt;strong&gt;Thor&lt;/strong&gt; jest oficjalnym narz&#281;dziem do instalacji Merba wraz z zale&#380;no&#347;ciami. Merb 0.9.8 ma ulepszony &lt;a href="http://merbunity.com/tutorials/15"&gt;cache&lt;/a&gt; oraz &lt;a href="http://github.com/carllerche/merb-core-enterprise-edition/wikis/whats-new-with-the-router"&gt;mechanizm routingu&lt;/a&gt; (uwaga: nie jest w pe&#322;ni zgodny wstecz) To jedno z ko&#324;cowych wi&#281;kszych zmian nie zachowuj&#261;cych wstecznej kompatybilno&#347;ci. Od Merba 0.9.9 nie powinno ju&#380; nic si&#281; zmieni&#263; w &lt;span class="caps"&gt;API&lt;/span&gt;.&lt;/p&gt;


	&lt;p&gt;Ci, co chcieliby instalowa&#263; sobie wersj&#281; edge pod Ubuntu z w&#322;&#261;czon&#261; opcj&#261; &lt;span class="caps"&gt;SECURE&lt;/span&gt;_PATH (vide: man sudo) mog&#261; mie&#263; ma&#322;e problemy ze &#347;cie&#380;kami je&#347;li instalowali (tak jak ja) Ruby w jakiej&#347; nietypowej &#347;cie&#380;ce (ja u&#380;ywam &lt;a href="http://www.rubyenterpriseedition.com/"&gt;Ruby Enterprise&lt;/a&gt;, kt&#243;ry domy&#347;lnie instaluje si&#281; w /opt/ruby-wersja). Ubuntu starsz&#261; komend&#281; &amp;#8220;sudo su&amp;#8221; uznaje te&#380; za przestarza&#322;&#261; i zamiast niej mo&#380;na u&#380;y&#263; &amp;#8220;sudo -i&amp;#8221;.&lt;/p&gt;


	&lt;p&gt;Zanim post&#261;pimy zgodnie z informacjami w artykule &lt;a href="http://wiki.merbivore.com/pages/getting-merb-and-datamapper-edge-step-by-step"&gt;Getting Merb and DataMapper Edge: Step-by-step&lt;/a&gt;, proponuj&#281; aby prze&#322;&#261;czy&#263; si&#281; na root&amp;#8217;a i ustawi&#263; dwie zmienne &#347;rodowiskowe wy&#322;&#261;czaj&#261;ce &lt;code&gt;sudo&lt;/code&gt; ze skrypt&#243;w instalacyjnych Merba i DataMappera:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_bash "&gt;sudo -i
export MERB_SUDO=&amp;quot; &amp;quot;
export SUDOLESS=&amp;quot; &amp;quot;   &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
      <pubDate>Mon, 15 Sep 2008 01:07:00 +0200</pubDate>
      <guid isPermaLink="false">urn:uuid:70434139-267c-40f2-9228-00b7cb231bd0</guid>
      <author>Jaros&#322;aw Zabie&#322;&#322;o</author>
      <link>http://blog.zabiello.com/articles/2008/09/15/merb-0-9-7</link>
      <category>ruby</category>
      <category>merb</category>
    </item>
    <item>
      <title>Merb 0.9.6</title>
      <description>&lt;p&gt;Ci, co instalowali sobie &lt;a href="http://merbivore.com/"&gt;Merba&lt;/a&gt; i robi&#261; sobie czasem aktualizacj&#281; gem&#243;w Rubiego, mog&#261; zauwa&#380;y&#263; &#380;e, co dwa tygodnie pojawia si&#281; kolejna jego wersja (w tej chwili jest to 0.9.6). Tak ma by&#263; a&#380; do pa&#378;dziernikowej wersji 1.0. Co ciekawe, synchronicznie z Merbem pojawia si&#281; zbli&#380;ona wersja &lt;a href="http://datamapper.org/"&gt;DataMappera&lt;/a&gt;. Nie jest to przypadek, bo deweloperzy obu projekt&#243;w &#347;ci&#347;le ze sob&#261; wsp&#243;&#322;pracuj&#261; (DataMapper 1.0 ma wyj&#347;&#263; razem z Merbem 1.0).&lt;/p&gt;


	&lt;p&gt;Wydaje si&#281;, te&#380; &#380;e &lt;a href="http://datamapper.org/"&gt;DataMapper&lt;/a&gt; zaczyna stawa&#263; si&#281; preferowanym &lt;span class="caps"&gt;ORM&lt;/span&gt;&amp;#8217;em dla Merba, mimo &#380;e Merb nie jest od niego uzale&#380;niony (tak jak Rails od Active Record) i r&#243;wnie dobrze wsp&#243;&#322;pracuje z innymi &lt;span class="caps"&gt;ORM&lt;/span&gt;&amp;#8217;ami napisanymi w Ruby, jak (b. dobry) &lt;a href="http://sequel.rubyforge.org/"&gt;Sequel&lt;/a&gt; czy wspomniany &lt;a href="http://ar.rubyonrails.org/"&gt;Active Record&lt;/a&gt;.&lt;/p&gt;


	&lt;p&gt;Merb aktualnie jest intensywnie szlifowany. Publiczne &lt;span class="caps"&gt;API&lt;/span&gt; jeszcze mo&#380;e ulec zmianie, wi&#281;c ci co u&#380;ywaj&#261; wersji bie&#380;&#261;cych musz&#261; &#347;ledzi&#263; to, co si&#281; zmienia. Po wyj&#347;ciu wersji 1.0 publiczne &lt;span class="caps"&gt;API&lt;/span&gt; ma by&#263; zamro&#380;one a&#380; do kolejnej wersji 2.0.&lt;/p&gt;


	&lt;p&gt;Bardzo ciekawie wygl&#261;da dodany niedawno do Merba &lt;a href="http://merbunity.com/tutorials/15"&gt;radykalnie nowy, modularny i 100% wielow&#261;tkowy cache&lt;/a&gt;. Dodano te&#380; inteligentniejsz&#261; regeneracj&#281; cache&amp;#8217;a. Aplikacja nie jest zwalniana procesem regeneracji cache&amp;#8217;a. Je&#347;li czas od&#347;wie&#380;enia przegl&#261;darki zbiegnie si&#281; z czasem od&#347;wie&#380;enia danych, Merb uruchamia taki proces dopiero &lt;em&gt;po&lt;/em&gt; wcze&#347;niejszym odes&#322;aniu starszych danych do klienta. Ulepszono te&#380; &lt;a href="http://merbunity.com/tutorials/17"&gt;spos&#243;b generowania projektu&lt;/a&gt;. Np. stworzenie nowego projektu, gdzie system testowania b&#281;dzie oparty na &lt;a href="http://rspec.info/"&gt;RSpec&lt;/a&gt;, silnikiem szablon&#243;w b&#281;dzie &lt;a href="http://haml.hamptoncatlin.com/"&gt;Haml&lt;/a&gt;, a &lt;span class="caps"&gt;ORM&lt;/span&gt;&amp;#8217;em &amp;#8211; &lt;a href="http://datamapper.org/"&gt;DataMapper&lt;/a&gt; mo&#380;na odpali&#263; za pomoc&#261; opcji generatora:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_bash "&gt;merb-gen app projekt --testing-framework=rspec \
                     --template-engine=haml \
                     --orm=datamapper&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Jednak to, co stawia Merba wyra&#380;nie wy&#380;ej od Rails to jego modularna budowa. Nie tylko mo&#380;na zamieni&#263; ca&#322;y projekt w gema. Dzi&#281;ki &lt;a href="http://merbivore.com/documentation/merb-more/head/merb-slices/index.html"&gt;slices&lt;/a&gt; mo&#380;na  ca&#322;&#261; aplikacj&#281; dos&#322;ownie posk&#322;ada&#263; z gem&#243;w. Moim zdaniem, jest to nawet lepiej zrobione ni&#380; w &lt;a href="http://djangoproject.com"&gt;Django&lt;/a&gt;.&lt;/p&gt;</description>
      <pubDate>Thu, 11 Sep 2008 00:22:00 +0200</pubDate>
      <guid isPermaLink="false">urn:uuid:cc0ca0cf-03a3-470d-9804-80e61ed94245</guid>
      <author>Jaros&#322;aw Zabie&#322;&#322;o</author>
      <link>http://blog.zabiello.com/articles/2008/09/11/merb-0-9-6</link>
      <category>merb</category>
      <category>ruby</category>
      <category>rails</category>
      <category>datamapper</category>
    </item>
    <item>
      <title>Django 1.0</title>
      <description>&lt;p&gt;&amp;#8220;Nie, to nie halucynacje, naprawd&#281; ju&#380; jest.&amp;#8221; Tak rozpoczyna si&#281; &lt;a href="http://www.djangoproject.com/weblog/2008/sep/03/1/"&gt;og&#322;oszenie&lt;/a&gt; odno&#347;nie wydania finalnej wersji Django 1.0. Troch&#281; za d&#322;ugo to trwa&#322;o. Prawd&#281; m&#243;wi&#261;c, nie wiem czy znajd&#281; jeszcze do&#347;&#263; si&#322; aby wg&#322;&#281;bia&#263; si&#281; ponownie w Django. Pylons 1.0 jest planowany na koniec roku. Rails 2.2 ma podobno wyj&#347;&#263; gdzie&#347; ko&#322;o pa&#378;dziernika. Ale najbardziej oczekuj&#281; na Merba 1.0 kt&#243;ry (wg plan&#243;w) ma by&#263; si&#281; pojawi&#263; 11 pa&#378;dziernika (termin &#322;&#261;czy si&#281; z konferencj&#261; &lt;a href="http://www.merbcamp.com/"&gt;Merbcamp&lt;/a&gt; 11-12 &lt;span class="caps"&gt;X 2008&lt;/span&gt; w San Diego gdzie pewnie Ezra Zygmuntowicz b&#281;dzie chcia&#322; zaprezentowa&#263; jego wersj&#281; finaln&#261;)&lt;/p&gt;</description>
      <pubDate>Thu, 04 Sep 2008 14:16:00 +0200</pubDate>
      <guid isPermaLink="false">urn:uuid:202b10a2-fce3-477a-8fcb-862d6454d9d4</guid>
      <author>Jaros&#322;aw Zabie&#322;&#322;o</author>
      <link>http://blog.zabiello.com/articles/2008/09/04/django10</link>
      <category>django</category>
      <category>python</category>
      <category>merb</category>
      <category>ruby</category>
    </item>
    <item>
      <title>Zen of Python - uwagi</title>
      <description>&lt;p&gt;Filozofi&#281; j&#281;zyka Python najlepiej oddaje tzw. Zen of Python. Jest ono dost&#281;pne w j&#281;z. angielskim z poziomu interpretera.&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="punct"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="ident"&gt;import&lt;/span&gt; &lt;span class="ident"&gt;this&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;ul&gt;
	&lt;li&gt;Beautiful is better than ugly.&lt;/li&gt;
		&lt;li&gt;Explicit is better than implicit.&lt;/li&gt;
		&lt;li&gt;Simple is better than complex. &lt;/li&gt;
		&lt;li&gt;Complex is better than complicated.&lt;/li&gt;
		&lt;li&gt;Flat is better than nested.&lt;/li&gt;
		&lt;li&gt;Sparse is better than dense.&lt;/li&gt;
		&lt;li&gt;Readability counts.                 &lt;/li&gt;
		&lt;li&gt;Special cases aren&amp;#8217;t special enough to break the rules.&lt;/li&gt;
		&lt;li&gt;Although practicality beats purity.           &lt;/li&gt;
		&lt;li&gt;Errors should never pass silently.&lt;/li&gt;
		&lt;li&gt;Unless explicitly silenced.&lt;/li&gt;
		&lt;li&gt;In the face of ambiguity, refuse the temptation to guess.&lt;/li&gt;
		&lt;li&gt;There should be one&amp;#8212;and preferably only one&amp;#8212;obvious way to do it.&lt;/li&gt;
		&lt;li&gt;Although that way may not be obvious at first unless you&amp;#8217;re Dutch.&lt;/li&gt;
		&lt;li&gt;Now is better than never.                                   &lt;/li&gt;
		&lt;li&gt;Although never is often better than &lt;strong&gt;right&lt;/strong&gt; now.&lt;/li&gt;
		&lt;li&gt;If the implementation is hard to explain, it&amp;#8217;s a bad idea.&lt;/li&gt;
		&lt;li&gt;If the implementation is easy to explain, it may be a good idea.&lt;/li&gt;
		&lt;li&gt;Namespaces are one honking great idea&amp;#8212;let&amp;#8217;s do more of those!&lt;/li&gt;
	&lt;/ul&gt;


	&lt;p&gt;W j&#281;zyku polskim brzmia&#322;oby to mniej wi&#281;cej tak:&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;Pi&#281;kny jest lepszy ni&#380; brzydki.&lt;/li&gt;
		&lt;li&gt;Jawny jest lepszy ni&#380; domy&#347;lny.&lt;/li&gt;
		&lt;li&gt;Prosty jest lepszy ni&#380; z&#322;o&#380;ony.&lt;/li&gt;
		&lt;li&gt;Z&#322;o&#380;ony jest lepszy ni&#380; skomplikowany.&lt;/li&gt;
		&lt;li&gt;P&#322;aski jest lepszy ni&#380; zagnie&#380;d&#380;ony.&lt;/li&gt;
		&lt;li&gt;Rzadki jest lepszy ni&#380; zag&#281;szczony.&lt;/li&gt;
		&lt;li&gt;Czytelno&#347;&#263; ma znaczenie.&lt;/li&gt;
		&lt;li&gt;Sytuacje wyj&#261;tkowe nie s&#261; na tyle wyj&#261;tkowe, aby &#322;ama&#263; regu&#322;y.&lt;/li&gt;
		&lt;li&gt;Aczkolwiek pragmatyzm wygrywa z puryzmem sztywnego trzymania si&#281; regu&#322;.&lt;/li&gt;
		&lt;li&gt;B&#322;&#281;dy zawsze powinny by&#263; sygnalizowane.&lt;/li&gt;
		&lt;li&gt;No chyba, &#380;e zostan&#261; celowo ukryte.&lt;/li&gt;
		&lt;li&gt;W obliczu dwuznaczno&#347;ci odrzu&#263; pokus&#281; aby zgadywa&#263;.&lt;/li&gt;
		&lt;li&gt;Powinien istnie&#263; jeden, i najlepiej tylko jeden, oczywisty spos&#243;b do zrobienia danej rzeczy.&lt;/li&gt;
		&lt;li&gt;Chocia&#380; spos&#243;b ten nie musi by&#263; pocz&#261;tkowo oczywisty je&#347;li nie jeste&#347; Holendrem.&lt;/li&gt;
		&lt;li&gt;Teraz jest lepsze ni&#380; nigdy.&lt;/li&gt;
		&lt;li&gt;Chocia&#380; nigdy jest cz&#281;sto lepsze ni&#380; &lt;strong&gt;w&#322;a&#347;nie&lt;/strong&gt; teraz.&lt;/li&gt;
		&lt;li&gt;&#377;le, je&#347;li implementacj&#281; jest trudno wyja&#347;ni&#263;.&lt;/li&gt;
		&lt;li&gt;Dobrze, je&#347;li implementacj&#281; jest &#322;atwo wyja&#347;ni&#263;.&lt;/li&gt;
		&lt;li&gt;Przestrzenie nazw s&#261; &#347;wietnym pomys&#322;em &amp;#8211; stw&#243;rzmy ich wi&#281;cej!&lt;/li&gt;
	&lt;/ul&gt;


	&lt;h2&gt;Explicite vs. implicite&lt;/h2&gt;


	&lt;p&gt;W przeciwie&#324;stwie do Rubiego, Python podkre&#347;la wy&#380;szo&#347;&#263; kodu  &lt;em&gt;explicite&lt;/em&gt; nad &lt;em&gt;implicite&lt;/em&gt; (jawnego nad domy&#347;lnym). W wypadku Pythona, wszelka informacja odno&#347;nie symboli obecnych w kodzie &#378;r&#243;d&#322;owym jest (zwykle) jednoznacznie okre&#347;lona i nie trzeba otwiera&#263; dziesi&#261;tk&#243;w innych plik&#243;w, aby si&#281; domy&#347;li&#263; sk&#261;d si&#281; dana funkcja, czy zmienna, wzi&#281;&#322;a. Ilo&#347;&#263; symboli dost&#281;pnych globalnie w Pythonie (w przestrzeni &lt;code&gt;__builtins__&lt;/code&gt;) jest relatywnie ma&#322;a i &#322;atwa do zapami&#281;tania. Reszta za&#347; mo&#380;e by&#263; wydedukowana z deklaracji importu.&lt;/p&gt;


	&lt;p&gt;(Istnieje co prawda mo&#380;liwo&#347;&#263; zaciemnienia tej przejrzysto&#347;ci za pomoc&#261; konstrukcji &lt;code&gt;from moj_modul import *&lt;/code&gt; ale generalnie nie zaleca si&#281; jej stosowania. W Ruby, a w Rails w szczeg&#243;lno&#347;ci, pr&#243;ba zlokalizowania kodu &#378;r&#243;d&#322;owego jest dosy&#263; mozolnym zaj&#281;ciem. Z samej deklaracji &lt;code&gt;require 'jakis_plik'&lt;/code&gt; (podobnie jak w &lt;span class="caps"&gt;PHP&lt;/span&gt;) nie wynika nic na temat dost&#281;pnych symboli w bie&#380;&#261;cej przestrzeni nazw. Trzeba otworzy&#263; plik i zobaczy&#263; co zosta&#322;o zadeklarowane. W wypadku wielokrotnych zagnie&#380;d&#380;e&#324; konstrukcji &lt;code&gt;require&lt;/code&gt; trzeba bawi&#263; si&#281; w Sherlocka Holmesa aby doj&#347;&#263; co si&#281; tam dzieje (swoj&#261; drog&#261; nadmiar zagnie&#380;d&#380;e&#324; jest sprzeczny z punktem &amp;#8220;P&#322;aski jest lepszy ni&#380; zagnie&#380;d&#380;ony&amp;#8221;). Konkurencyjny do Rails framework &amp;#8211; &lt;a href="http://merbivore.com/"&gt;Merb&lt;/a&gt; &amp;#8211; postanowi&#322; zm zminimalizowa&#263; ilo&#347;&#263; magii (tj. domy&#347;lnych deklaracji) w kodzie do minimum. Wi&#281;c, jak wida&#263;, da si&#281;. Osobi&#347;cie Merb jest moim faworytem je&#347;li chodzi o webowe frameworki. Jest szybki, prosty i czytelny. Zbudowany na solidnych, pragmatycznych, in&#380;ynierskich zasadach. Na 11 pa&#378;dziernika 2008 zapowiadana jest wersja ko&#324;cowa 1.0.)&lt;/p&gt;


	&lt;p&gt;Jak wi&#281;kszo&#347;&#263; rzeczy, istnieje te&#380; druga strona medalu. &amp;#8220;Magiczne&amp;#8221; podej&#347;cie przyj&#281;te w Rubim mo&#380;e nie wp&#322;ywa dodatnio na kwesti&#281; oczywisto&#347;ci (pkt. 1 Zen of Python) ale daje za to mo&#380;liwo&#347;&#263; uzyskania pi&#281;kniejszego kodu (pkt.1 Zen of Python) Uzyskanie tak &#322;adnego &lt;a href="http://en.wikipedia.org/wiki/Domain-specific_programming_language"&gt;&lt;span class="caps"&gt;DSL&lt;/span&gt;&amp;#8217;a&lt;/a&gt; jak RSPec jest w Pythonie (i wi&#281;kszo&#347;ci j&#281;zyk&#243;w) po prostu niemo&#380;liwe. Zobacz te&#380; &lt;a href="http://bnl.jayfields.com/"&gt;Business Natural Languages&lt;/a&gt; (oraz &lt;a href="http://www.infoq.com/presentations/fields-business-natural-languages-ruby"&gt;prezentacj&#281;&lt;/a&gt;) Programi&#347;ci Rubiego podkre&#347;laj&#261; walory estetyczne sk&#322;adni Rubiego i tu maj&#261; racj&#281;.&lt;/p&gt;


	&lt;h2&gt;Jedna droga do celu&lt;/h2&gt;


	&lt;p&gt;Pythonowcy mocno podkre&#347;laj&#261; zasad&#281; &amp;#8220;Powinien istnie&#263; jeden, i najlepiej tylko jeden, oczywisty spos&#243;b do zrobienia danej rzeczy.&amp;#8221; Niestety, zasada ta nie zawsze jest stosowana. Najlepszym przyk&#322;adem jest &lt;a href="http://www.sqlalchemy.org/"&gt;SQLAlchemy&lt;/a&gt;, kt&#243;ry wydaje si&#281; kompletnie ignorowa&#263; t&#261; zasad&#281;. Nie ujmuj&#261;c jego mo&#380;liwo&#347;ci, spos&#243;b jego u&#380;ycia jest tak nieoczywisty, &#380;e powsta&#322;y nawet nak&#322;adki na warstw&#281; &lt;span class="caps"&gt;API&lt;/span&gt; SQLAlchemy (&lt;a href="http://elixir.ematia.de/trac/wiki"&gt;Elixir&lt;/a&gt;). Tak&#380;e &lt;a href="http://aspn.activestate.com/ASPN/Mail/Message/Jython-users/2034708"&gt;spos&#243;b u&#380;ycia w&#261;tk&#243;w w Jythonie&lt;/a&gt; niespecjalnie pasuje do jednego, oczywistego rozwi&#261;zania.  Ale pomijaj&#261;c takie przypadki, og&#243;lnie zasada &amp;#8220;jednego sposobu&amp;#8221; wydaje si&#281; dobra.&lt;/p&gt;


	&lt;p&gt;Osoby poznaj&#261;ce Rubiego na pocz&#261;tku mog&#261; by&#263; zdezorientowania setkami dost&#281;pnych metod w prawie ka&#380;dym obiekcie. Pocz&#261;tkowo tak&#380;e i mi wydawa&#322;o si&#281; oczywiste, &#380;e powy&#380;sza zasada Zen Pythona jest lepsza ni&#380;, dziedziczone po Perlu, nastawienie na mo&#380;liwo&#347;&#263; wielu rozwi&#261;za&#324; tego samego zagadnienia. Jednak&#380;e, w miar&#281; &amp;#8220;otrzaskania&amp;#8221; si&#281; ze sk&#322;adni&#261; i metodami Rubiego, zasada &amp;#8220;jednej drogi&amp;#8221; przesta&#322;a by&#263; a&#380; tak wa&#380;na. Faktem jest &#380;e Ruby dysponuje wi&#281;kszym arsena&#322;em metod i konstrukcji ni&#380; Python (i przez to trudniej si&#281; go opanowa&#263; ni&#380; Pythona), ale dzi&#281;ki nim mo&#380;na pisa&#263; znacznie bardziej zwarty kod i to bez wi&#281;kszej utraty czytelno&#347;ci tak charakterystycznej dla Perla. Ruby &#347;wietnie si&#281; nadaje na jednolinijkowe skrypty zamiast Basha czy Pythona.&lt;/p&gt;


	&lt;h2&gt;Programowanie jest sztuk&#261;&lt;/h2&gt;


	&lt;p&gt;Nawet najlepsze zasady na jakich z budowany by&#322;by j&#281;zyk nie zagwarantuj&#261; &#380;e kod w tym j&#281;zyku automatycznie b&#281;dzie czytelny i &#322;adny. Nawet w Pythonie mo&#380;na stworzy&#263; &amp;#8220;potworki&amp;#8221; sk&#322;adniowe. Programista mo&#380;e by&#263; wyrobnikiem albo artyst&#261;. Na pewno tym drugim nie zostanie ten, kto programowania  po prostu nie lubi. Tak nawiasem m&#243;wi&#261;c, w obecnych czasach, kiedy trudno jest znale&#378;&#263; dobrych programist&#243;w, dobrym wska&#378;nikiem mo&#380;e by&#263; to, na ile programowanie jest czyj&#261;&#347; &lt;em&gt;pasj&#261;&lt;/em&gt;. Pasjonaci bardzo szybko si&#281; ucz&#261; i prze&#347;cigaj&#261; tych, co traktuj&#261; programowanie tylko jako zaj&#281;cie do zarabiania pieni&#281;dzy.&lt;/p&gt;


	&lt;p&gt;Znajomo&#347;&#263; j&#281;zyka to nie tylko nauczenie si&#281; na pami&#281;&#263; jego sk&#322;adni i bibliotek. Ka&#380;dy j&#281;zyk ma sw&#243;j &amp;#8220;spos&#243;b my&#347;lenia&amp;#8221;. Np. spos&#243;b optymalnego u&#380;ycia Pythona/Rubiego bardzo si&#281; r&#243;&#380;ni od sposobu pracy w j&#281;zykach takich jak Java/C++. Bywa te&#380;, &#380;e to, co tam jest tak gloryfikowane, w j&#281;zyku dynamicznym staje si&#281; &#347;miesznie &#322;atwe albo zb&#281;dne. Ruby nie potrzebuje &amp;#8220;dependency injection&amp;#8221; bo to samo mo&#380;na uzyska&#263; znacznie pro&#347;ciej na bazie samej swej sk&#322;adni. Python z kolei nie potrzebuje specjalnych konstrukcji dla stworzenia &amp;#8220;singletona&amp;#8221;, bo wystarczy mu do tego zwyk&#322;y modu&#322;. Itp. itd. Z praktyki widz&#281;, &#380;e trzeba mniej wi&#281;cej oko&#322;o roku aby javowiec pozby&#322; si&#281; starych nawyk&#243;w i &amp;#8220;poczu&#322;&amp;#8221; Ruby Way.&lt;/p&gt;</description>
      <pubDate>Mon, 01 Sep 2008 13:42:00 +0200</pubDate>
      <guid isPermaLink="false">urn:uuid:d82b4a76-a1c9-4ee7-bb28-16621fd423a3</guid>
      <author>Jaros&#322;aw Zabie&#322;&#322;o</author>
      <link>http://blog.zabiello.com/articles/2008/09/01/zen-of-python</link>
      <category>python</category>
      <category>ruby</category>
    </item>
    <item>
      <title>Ruby, Python i natywne w&#261;tki systemu operacyjnego</title>
      <description>&lt;p&gt;Wiele si&#281; m&#243;wi o tym, &#380;e Ruby jak i Python nie posiadaj&#261; obs&#322;ugi natywnych w&#261;tk&#243;w systemu operacyjnego. Wbudowane, tzw. &lt;em&gt;green threads&lt;/em&gt;, nie s&#261; w stanie wykorzysta&#263; zalet maszyn wyposa&#380;onych w procesory wielordzeniowe. Istniej&#261; jednak implementacje obu j&#281;zyk&#243;w w czystej Javie. Czy ich u&#380;ycie daje jakie&#347; znacz&#261;ce przy&#347;pieszenie?&lt;/p&gt;


	&lt;p&gt;Wszystkie testy by&#322;y wykonywane na MacBook Pro Core2 Duo 2.16GHZ, 4GB &lt;span class="caps"&gt;RAM&lt;/span&gt; i systemie Mac &lt;span class="caps"&gt;OS X 10&lt;/span&gt;.5.4 Leopard + zainstalowana Java 1.6.0_05.&lt;/p&gt;


	&lt;h2&gt;Python&lt;/h2&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="ident"&gt;from&lt;/span&gt; &lt;span class="ident"&gt;time&lt;/span&gt; &lt;span class="ident"&gt;import&lt;/span&gt; &lt;span class="ident"&gt;time&lt;/span&gt;
&lt;span class="ident"&gt;from&lt;/span&gt; &lt;span class="ident"&gt;random&lt;/span&gt; &lt;span class="ident"&gt;import&lt;/span&gt; &lt;span class="constant"&gt;Random&lt;/span&gt;
&lt;span class="ident"&gt;from&lt;/span&gt; &lt;span class="ident"&gt;threading&lt;/span&gt; &lt;span class="ident"&gt;import&lt;/span&gt; &lt;span class="constant"&gt;Thread&lt;/span&gt;
&lt;span class="ident"&gt;rand&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Random&lt;/span&gt;&lt;span class="punct"&gt;().&lt;/span&gt;&lt;span class="ident"&gt;randint&lt;/span&gt; &lt;span class="comment"&gt;# alias&lt;/span&gt;

&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;Test(Thread):&lt;/span&gt;
   &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;__init__&lt;/span&gt; &lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;self&lt;/span&gt;&lt;span class="punct"&gt;):&lt;/span&gt; 
      &lt;span class="constant"&gt;Thread&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;__init__&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;self&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
      &lt;span class="ident"&gt;print&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;Starting %s&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt; &lt;span class="punct"&gt;%&lt;/span&gt; &lt;span class="constant"&gt;self&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;getName&lt;/span&gt;&lt;span class="punct"&gt;()&lt;/span&gt;
   &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;run&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;self&lt;/span&gt;&lt;span class="punct"&gt;):&lt;/span&gt; 
      &lt;span class="ident"&gt;a&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="ident"&gt;rand&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="number"&gt;0&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt;&lt;span class="constant"&gt;SIZE&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt; &lt;span class="keyword"&gt;for&lt;/span&gt; &lt;span class="ident"&gt;x&lt;/span&gt; &lt;span class="keyword"&gt;in&lt;/span&gt; &lt;span class="ident"&gt;xrange&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;SIZE&lt;/span&gt;&lt;span class="punct"&gt;)]&lt;/span&gt;
      &lt;span class="ident"&gt;a&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;sort&lt;/span&gt;&lt;span class="punct"&gt;()&lt;/span&gt;
      &lt;span class="ident"&gt;print&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;%s finished&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt; &lt;span class="punct"&gt;%&lt;/span&gt; &lt;span class="constant"&gt;self&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;getName&lt;/span&gt;&lt;span class="punct"&gt;()&lt;/span&gt;      

&lt;span class="ident"&gt;print&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;Start&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;
&lt;span class="ident"&gt;start&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;time&lt;/span&gt;&lt;span class="punct"&gt;()&lt;/span&gt;
&lt;span class="constant"&gt;THREADS&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="constant"&gt;SIZE&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="number"&gt;20&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="number"&gt;100000&lt;/span&gt;
&lt;span class="ident"&gt;threads&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;[]&lt;/span&gt;             
&lt;span class="keyword"&gt;for&lt;/span&gt; &lt;span class="ident"&gt;i&lt;/span&gt; &lt;span class="keyword"&gt;in&lt;/span&gt; &lt;span class="ident"&gt;xrange&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;THREADS&lt;/span&gt;&lt;span class="punct"&gt;):&lt;/span&gt;
    &lt;span class="ident"&gt;t&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Test&lt;/span&gt;&lt;span class="punct"&gt;()&lt;/span&gt;
    &lt;span class="ident"&gt;threads&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;append&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;t&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
    &lt;span class="ident"&gt;t&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;start&lt;/span&gt;&lt;span class="punct"&gt;()&lt;/span&gt;     
&lt;span class="keyword"&gt;while&lt;/span&gt; &lt;span class="constant"&gt;True&lt;/span&gt; &lt;span class="keyword"&gt;in&lt;/span&gt; &lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="ident"&gt;t&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;isAlive&lt;/span&gt;&lt;span class="punct"&gt;()&lt;/span&gt; &lt;span class="keyword"&gt;for&lt;/span&gt; &lt;span class="ident"&gt;t&lt;/span&gt; &lt;span class="keyword"&gt;in&lt;/span&gt; &lt;span class="ident"&gt;threads&lt;/span&gt;&lt;span class="punct"&gt;]:&lt;/span&gt;
    &lt;span class="ident"&gt;pass&lt;/span&gt;
&lt;span class="ident"&gt;print&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;Time: %s s&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt; &lt;span class="punct"&gt;%&lt;/span&gt; &lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;time&lt;/span&gt;&lt;span class="punct"&gt;()&lt;/span&gt; &lt;span class="punct"&gt;-&lt;/span&gt; &lt;span class="ident"&gt;start&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt; &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Dla powy&#380;szego kodu Python i Jython uzyska&#322;y wyniki:&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;Jython 2.2.1 = 12.15 s.&lt;/li&gt;
		&lt;li&gt;Python 2.5.2 = 14.24 s.&lt;/li&gt;
	&lt;/ul&gt;


	&lt;p&gt;Ro&#380;nica jako&#347; podejrzanie ma&#322;a wskazuj&#261;ca na wci&#261;&#380; jeszcze niedojrza&#322;&#261; implementacj&#281; Jythona. Dla pewno&#347;ci, zmodyfikowa&#322;em kod tak, aby korzysta&#322; z natywnych bibliotek Javy.&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="ident"&gt;from&lt;/span&gt; &lt;span class="ident"&gt;time&lt;/span&gt; &lt;span class="ident"&gt;import&lt;/span&gt; &lt;span class="ident"&gt;time&lt;/span&gt;
&lt;span class="ident"&gt;from&lt;/span&gt; &lt;span class="ident"&gt;random&lt;/span&gt; &lt;span class="ident"&gt;import&lt;/span&gt; &lt;span class="constant"&gt;Random&lt;/span&gt;
&lt;span class="ident"&gt;rand&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Random&lt;/span&gt;&lt;span class="punct"&gt;().&lt;/span&gt;&lt;span class="ident"&gt;randint&lt;/span&gt; &lt;span class="comment"&gt;# alias&lt;/span&gt;
&lt;span class="ident"&gt;from&lt;/span&gt; &lt;span class="ident"&gt;java&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;lang&lt;/span&gt; &lt;span class="ident"&gt;import&lt;/span&gt; &lt;span class="constant"&gt;Thread&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="constant"&gt;Runnable&lt;/span&gt;

&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;Test(Runnable):&lt;/span&gt;
   &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;__init__&lt;/span&gt; &lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;self&lt;/span&gt;&lt;span class="punct"&gt;):&lt;/span&gt; 
      &lt;span class="ident"&gt;print&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;Starting %s&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt; &lt;span class="punct"&gt;%&lt;/span&gt; &lt;span class="constant"&gt;self&lt;/span&gt;
   &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;run&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;self&lt;/span&gt;&lt;span class="punct"&gt;):&lt;/span&gt;         
      &lt;span class="ident"&gt;a&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="ident"&gt;rand&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="number"&gt;0&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt;&lt;span class="constant"&gt;SIZE&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt; &lt;span class="keyword"&gt;for&lt;/span&gt; &lt;span class="ident"&gt;x&lt;/span&gt; &lt;span class="keyword"&gt;in&lt;/span&gt; &lt;span class="ident"&gt;xrange&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;SIZE&lt;/span&gt;&lt;span class="punct"&gt;)]&lt;/span&gt;
      &lt;span class="ident"&gt;a&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;sort&lt;/span&gt;&lt;span class="punct"&gt;()&lt;/span&gt;  
      &lt;span class="ident"&gt;print&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;%s finished&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt; &lt;span class="punct"&gt;%&lt;/span&gt; &lt;span class="constant"&gt;self&lt;/span&gt;

&lt;span class="ident"&gt;print&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;Start&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;
&lt;span class="ident"&gt;start&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;time&lt;/span&gt;&lt;span class="punct"&gt;()&lt;/span&gt;
&lt;span class="constant"&gt;THREADS&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="constant"&gt;SIZE&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="number"&gt;20&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="number"&gt;100000&lt;/span&gt;    
&lt;span class="ident"&gt;threads&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;[]&lt;/span&gt;             
&lt;span class="keyword"&gt;for&lt;/span&gt; &lt;span class="ident"&gt;i&lt;/span&gt; &lt;span class="keyword"&gt;in&lt;/span&gt; &lt;span class="ident"&gt;xrange&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;THREADS&lt;/span&gt;&lt;span class="punct"&gt;):&lt;/span&gt;
    &lt;span class="ident"&gt;t&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Thread&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;Test&lt;/span&gt;&lt;span class="punct"&gt;())&lt;/span&gt;              
    &lt;span class="ident"&gt;threads&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;append&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;t&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
    &lt;span class="ident"&gt;t&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;start&lt;/span&gt;&lt;span class="punct"&gt;()&lt;/span&gt;     
&lt;span class="keyword"&gt;while&lt;/span&gt; &lt;span class="constant"&gt;True&lt;/span&gt; &lt;span class="keyword"&gt;in&lt;/span&gt; &lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="ident"&gt;t&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;isAlive&lt;/span&gt;&lt;span class="punct"&gt;()&lt;/span&gt; &lt;span class="keyword"&gt;for&lt;/span&gt; &lt;span class="ident"&gt;t&lt;/span&gt; &lt;span class="keyword"&gt;in&lt;/span&gt; &lt;span class="ident"&gt;threads&lt;/span&gt;&lt;span class="punct"&gt;]:&lt;/span&gt;
    &lt;span class="ident"&gt;pass&lt;/span&gt;
&lt;span class="ident"&gt;print&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;Time: %s s&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt; &lt;span class="punct"&gt;%&lt;/span&gt; &lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;time&lt;/span&gt;&lt;span class="punct"&gt;()&lt;/span&gt; &lt;span class="punct"&gt;-&lt;/span&gt; &lt;span class="ident"&gt;start&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt; &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Tym razem&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;Jython 2.2.1 = 11.96 s.&lt;/li&gt;
	&lt;/ul&gt;


	&lt;p&gt;R&#243;&#380;nica jest minimalna. Na dodatek panuje troch&#281; zamieszania co do sposobu odpalania w&#261;tk&#243;w w Jythonie &amp;#8211; &lt;a href="http://aspn.activestate.com/ASPN/Mail/Message/Jython-users/2034708"&gt;m&#281;tna sk&#322;adnia i za du&#380;o mo&#380;liwych sposob&#243;w&lt;/a&gt; uzyskania tego samego efektu. Po SQLAlchemy, Jython jest kolejnym przyk&#322;adam ca&#322;kowitej ignorancji za&#322;o&#380;e&#324; j&#281;zyka Python (o istnieniu jednej, oczywistej drogi do tego samego celu). Na domiar z&#322;ego, m&#243;j pierwotny test zak&#322;ada&#322; testowanie miliona liczb do sortowania. Jython nie by&#322; w stanie tego testu wykona&#263; z powodu braku pami&#281;ci dla Javy. Ruszy&#322; dopiero jak mu zaalokowa&#322;em 1GB (s&#322;ownie: jeden gigabajt pami&#281;ci) za pomoc&#261; opcji (-Xmx1024M), co jest po prostu chore! Po wymianie pierwotnego &lt;code&gt;range()&lt;/code&gt; na generatorowy &lt;code&gt;xrange()&lt;/code&gt; zapotrzebowanie na pami&#281;&#263; wyra&#378;nie zmala&#322;o i wystarczy&#322;a ju&#380; opcja -Xmx256M. Jednak&#380;e kod si&#281; wykonywa&#322;&#160;tak koszmarnie wolno, &#380;e nie starczy&#322;o mi cierpliwo&#347;ci i zmniejszy&#322;em ilo&#347;&#263; iteracji do 100 tys.&lt;/p&gt;


	&lt;h2&gt;Ruby&lt;/h2&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="ident"&gt;require&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;time&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;
&lt;span class="ident"&gt;require&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;thread&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;

&lt;span class="constant"&gt;THREADS&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="constant"&gt;SIZE&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="number"&gt;20&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="number"&gt;100_000&lt;/span&gt;

&lt;span class="ident"&gt;start&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Time&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;now&lt;/span&gt;
&lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;Start&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;
&lt;span class="ident"&gt;threads&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="number"&gt;1&lt;/span&gt;&lt;span class="punct"&gt;..&lt;/span&gt;&lt;span class="constant"&gt;THREADS&lt;/span&gt;&lt;span class="punct"&gt;).&lt;/span&gt;&lt;span class="ident"&gt;map&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;i&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt;
  &lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;Starting Thread-&lt;span class="expr"&gt;#{i}&lt;/span&gt;&lt;span class="escape"&gt;\n&lt;/span&gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;
  &lt;span class="constant"&gt;Thread&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;i&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;t&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt;
    &lt;span class="ident"&gt;a&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="number"&gt;1&lt;/span&gt;&lt;span class="punct"&gt;..&lt;/span&gt;&lt;span class="constant"&gt;SIZE&lt;/span&gt;&lt;span class="punct"&gt;).&lt;/span&gt;&lt;span class="ident"&gt;map&lt;/span&gt; &lt;span class="punct"&gt;{|&lt;/span&gt;&lt;span class="ident"&gt;e&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt; &lt;span class="ident"&gt;rand&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;SIZE&lt;/span&gt;&lt;span class="punct"&gt;)}&lt;/span&gt;
    &lt;span class="ident"&gt;a&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;sort!&lt;/span&gt;
    &lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;Thread-&lt;span class="expr"&gt;#{t}&lt;/span&gt; ended&lt;span class="escape"&gt;\n&lt;/span&gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="keyword"&gt;while&lt;/span&gt; &lt;span class="ident"&gt;t&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;threads&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;find&lt;/span&gt; &lt;span class="punct"&gt;{|&lt;/span&gt;&lt;span class="ident"&gt;lt&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt; &lt;span class="ident"&gt;lt&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;alive?&lt;/span&gt;&lt;span class="punct"&gt;}&lt;/span&gt;
  &lt;span class="ident"&gt;t&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;join&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt; 
&lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;Time: &lt;span class="expr"&gt;#{Time.now - start}&lt;/span&gt; s.&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Pierwsze, co mi si&#281; od razu rzuca w oczy, to o wiele czytelniejsza, zgrzebniejsza sk&#322;adnia Rubiego, kt&#243;ry tu korzysta z blok&#243;w kodu. Po drugie, wyniki s&#261; dosy&#263; ciekawe:&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;Ruby 1.9.0 = 1.11 s&lt;/li&gt;
		&lt;li&gt;Ruby Enterprise = 2.77 s&lt;/li&gt;
		&lt;li&gt;JRuby 1.1.2 = 3.53 s&lt;/li&gt;
		&lt;li&gt;Ruby 1.8.7 = 21.82 s.&lt;/li&gt;
	&lt;/ul&gt;


	&lt;p&gt;Ruby okaza&#322; si&#281; najwolniejszy w tym zestawieniu. Python by&#322; tylko troch&#281; szybszy. JRuby, korzystaj&#261;cy z javowych w&#261;tk&#243;w systemowych, zdeklasowa&#322; Rubiego, Pythona i niedojrza&#322;ego Jythona. Jednak&#380;e to nie JRuby okaza&#322; si&#281; tu zwyci&#281;zc&#261;. Nie trzeba czeka&#263; na Ruby 2.0, wersja 1.9 posiada ju&#380; natywn&#261; obs&#322;ug&#281; w&#261;tk&#243;w &lt;span class="caps"&gt;POSIX&lt;/span&gt; i jest dodatkowo nie&#378;le zoptymalizowana. Ruby 1.9 pokaza&#322;, &#380;e jest tu prawie 4x szybszy od JRuby. Nie s&#261;dz&#281;, &#380;e t&#261; szybko&#347;&#263; uzyska&#322; na lepszej implementacji w&#261;tk&#243;w od Javy. Raczej ma mocno zoptymalizowany kod kt&#243;ry by&#322; wykonywany w ka&#380;dym z w&#261;tk&#243;w.&lt;/p&gt;


	&lt;p&gt;Bardzo dobrze poradzi&#322; sobie te&#380; &lt;a href="http://www.rubyenterpriseedition.com/"&gt;Ruby Enterprise&lt;/a&gt;, zoptymalizowana wersja Ruby 1.8.6 przez tw&#243;rc&#243;w &lt;a href="http://www.modrails.com/"&gt;Passengera&lt;/a&gt;! Nie wiem jakim cudem Ruby Enterprise pobi&#322;&#160;JRubiego&amp;#8230; no chyba, &#380;e jego tw&#243;rcy dodali mu obs&#322;ug&#281; natywnych w&#261;tk&#243;w systemu operacyjnego. Inaczej nie mog&#281; sobie wyt&#322;umaczy&#263; tak dobrego wyniku.&lt;/p&gt;


	&lt;h2&gt;Updated&lt;/h2&gt;


	&lt;p&gt;Dla pe&#322;niejszego obrazu uruchomi&#322;em testy dla 1 w&#261;tku. Poprawi&#322;em te&#380; b&#322;&#261;d z ilo&#347;ci&#261; list do sortowania faworyzuj&#261;c&#261; Rubiego. Ostateczne podsumowanie wygl&#261;da tak:&lt;/p&gt;


	&lt;p&gt;1 thread, 2,000,000 iterations&lt;/p&gt;


	&lt;ol&gt;
	&lt;li&gt;Ruby 1.9 = 1.69 s.   &lt;/li&gt;
		&lt;li&gt;Ruby Enterprise = 3.38 s.&lt;/li&gt;
		&lt;li&gt;JRuby 1.1.2 = 7.06 s.&lt;/li&gt;
		&lt;li&gt;Jython 2.2.1 = 17.29 s.&lt;/li&gt;
		&lt;li&gt;Python 2.5.2 = 18.06 s.&lt;/li&gt;
		&lt;li&gt;Ruby 1.8.7 = 22.37 s.&lt;/li&gt;
	&lt;/ol&gt;


	&lt;p&gt;20 threads * 100,000 iterations&lt;/p&gt;


	&lt;ol&gt;
	&lt;li&gt;Ruby 1.9 = 1.54 s.   &lt;/li&gt;
		&lt;li&gt;Ruby Enterprise = 3.01 s.           &lt;/li&gt;
		&lt;li&gt;JRuby 1.1.2 = 5.82 s.&lt;/li&gt;
		&lt;li&gt;Jython 2.2.1 = 11.86 s.&lt;/li&gt;
		&lt;li&gt;Python 2.5.2 = 12.32 s.                                                  &lt;/li&gt;
		&lt;li&gt;Ruby 1.8.7 = 22.68 s.&lt;/li&gt;
	&lt;/ol&gt;


	&lt;p&gt;Czasy, kiedy Python by&#322;&#160;zawsze szybszy od Rubiego, to ju&#380; przesz&#322;o&#347;&#263;. Z wynik&#243;w wynika, &#380;e to nie obs&#322;uga w&#261;tk&#243;w zadecydowa&#322;a o wynikach. Ruby 1.9 pobi&#322;&#160;wszystkich zar&#243;wno w te&#347;cie 1 jak i wielu w&#261;tk&#243;w.&lt;/p&gt;


	&lt;h2&gt;Updated 2008-07-30&lt;/h2&gt;


	&lt;p&gt;Poprawi&#322;em troch&#281; test, aby nie zu&#380;ywa&#322; tyle pami&#281;ci. Wyrzuci&#322;em wi&#281;c generowanie list i sortownie. Zosta&#322;o samo generowanie losowych liczb. Doda&#322;em te&#380; kod dla Javy dla por&#243;wnania.&lt;/p&gt;


	&lt;h3&gt;Java&lt;/h3&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_java "&gt;import java.util.Random;

public class Main {

  static Integer SIZE,  ITERATIONS;

  public static void main(String[] args) throws Exception {
    Integer[] threads_nr = {1, 10, 50, 100};
    SIZE = Integer.parseInt(args[1]);
    System.out.println(args[0]);
    for(Integer nr: threads_nr) {
      ITERATIONS = SIZE / nr;
      System.out.printf(&amp;quot; %3d thread(s) x %9s = &amp;quot;, nr, ITERATIONS);
      long start = System.currentTimeMillis();
      Thread[] threads = new Thread[nr];
      for(int i = 0; i &amp;lt; threads.length; i++) {
        threads[i] = new ThreadTest();
        threads[i].start();
      }
      while(threadsAlive(threads)) {}
      System.out.printf(&amp;quot;%s s.\n&amp;quot;, (System.currentTimeMillis() - start) / 1000.0);
    }
  }

  public static boolean threadsAlive(Thread[] threads) {
    for(Thread t: threads)
      if(t.isAlive())
        return true;
    return false;
  }

  static class ThreadTest extends Thread {

    @Override
    public void run() {
      Random rnd = new Random();
      for(int i = 0; i &amp;lt; ITERATIONS; i++)
        rnd.nextInt(SIZE);
    }
  }
}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Test:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_bash "&gt;$ java Main &amp;quot;`java -version`&amp;quot; 10000000
java version &amp;quot;1.6.0_05&amp;quot;
Java(TM) SE Runtime Environment (build 1.6.0_05-b13-120)
Java HotSpot(TM) 64-Bit Server VM (build 1.6.0_05-b13-52, mixed mode)
  1 thread(s) x  10000000 = 0.361 s.
 10 thread(s) x   1000000 = 0.18 s.
 50 thread(s) x    200000 = 0.186 s.
100 thread(s) x    100000 = 0.189 s.  &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Java, co nie dziwi, jest najszybsza. Nie ma znacz&#261;cej r&#243;&#380;nicy mi&#281;dzy 10 czy 10 w&#261;tkami, bo m&#243;j procesor posiada tylko dwa rdzenie.&lt;/p&gt;


	&lt;h3&gt;Ruby/JRuby&lt;/h3&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="ident"&gt;require&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;time&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;
&lt;span class="ident"&gt;require&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;thread&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;

&lt;span class="constant"&gt;SIZE&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;ARGV&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="number"&gt;1&lt;/span&gt;&lt;span class="punct"&gt;].&lt;/span&gt;&lt;span class="ident"&gt;to_i&lt;/span&gt;  
&lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="constant"&gt;ARGV&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="number"&gt;0&lt;/span&gt;&lt;span class="punct"&gt;]&lt;/span&gt;   
&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="number"&gt;1&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="number"&gt;10&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="number"&gt;50&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="number"&gt;100&lt;/span&gt;&lt;span class="punct"&gt;].&lt;/span&gt;&lt;span class="ident"&gt;each&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;nr&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt;
  &lt;span class="ident"&gt;iterations&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;SIZE&lt;/span&gt; &lt;span class="punct"&gt;/&lt;/span&gt; &lt;span class="ident"&gt;nr&lt;/span&gt;
  &lt;span class="ident"&gt;print&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt; %3d thread(s) x %9s = &lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt; &lt;span class="punct"&gt;%&lt;/span&gt; &lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="ident"&gt;nr&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;iterations&lt;/span&gt;&lt;span class="punct"&gt;]&lt;/span&gt;
  &lt;span class="ident"&gt;start&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Time&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;now&lt;/span&gt;
  &lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="number"&gt;1&lt;/span&gt;&lt;span class="punct"&gt;..&lt;/span&gt;&lt;span class="ident"&gt;nr&lt;/span&gt;&lt;span class="punct"&gt;).&lt;/span&gt;&lt;span class="ident"&gt;map&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;i&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt;
    &lt;span class="constant"&gt;Thread&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;i&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;t&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt;
      &lt;span class="ident"&gt;iterations&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;times&lt;/span&gt; &lt;span class="punct"&gt;{&lt;/span&gt;&lt;span class="ident"&gt;rand&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;SIZE&lt;/span&gt;&lt;span class="punct"&gt;)}&lt;/span&gt;
    &lt;span class="keyword"&gt;end&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;each&lt;/span&gt; &lt;span class="punct"&gt;{|&lt;/span&gt;&lt;span class="ident"&gt;t&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt; &lt;span class="ident"&gt;t&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;join&lt;/span&gt;&lt;span class="punct"&gt;}&lt;/span&gt;
  &lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="constant"&gt;Time&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;now&lt;/span&gt; &lt;span class="punct"&gt;-&lt;/span&gt; &lt;span class="ident"&gt;start&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Ten sam kod w Ruby/JRuby wygl&#261;da znacznie kr&#243;cej (i &#322;adniej) ale kosztem wydajno&#347;ci. To te&#380; nie dziwi. Ruby jest bardzo produktywnym j&#281;zykiem, lecz oczywi&#347;cie nie tak szybkim jak Java.&lt;/p&gt;


	&lt;p&gt;Wyniki test&#243;w:&lt;/p&gt;


	&lt;p&gt;Ruby 1.9:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_bash "&gt;$ ruby1.9 main.rb &amp;quot;`ruby1.9 -v`&amp;quot; 10_000_000
ruby 1.9.0 (2008-06-20 revision 17482) [i686-darwin9.4.0]
  1 thread(s) x  10000000 = 2.858588
 10 thread(s) x   1000000 = 2.832928
 50 thread(s) x    200000 = 2.845377
100 thread(s) x    100000 = 2.852745&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;JRuby:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_bash "&gt;$ jruby main.rb &amp;quot;`jruby -v`&amp;quot; 10_000_000
jruby 1.1.3 (ruby 1.8.6 patchlevel 114) (2008-07-28 rev 6586) [x86_64-java]
   1 thread(s) x  10000000 = 3.58
  10 thread(s) x   1000000 = 3.4290000000000003
  50 thread(s) x    200000 = 3.442
 100 thread(s) x    100000 = 3.516&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Ruby Enterprise:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_bash "&gt;$ ruby-enterprise main.rb &amp;quot;`ruby-enterprise -v`&amp;quot; 10_000_000
ruby 1.8.6 (2008-03-03 patchlevel 114) [i686-darwin9.4.0]
  1 thread(s) x  10000000 = 3.510694
 10 thread(s) x   1000000 = 3.552756
 50 thread(s) x    200000 = 3.586885
100 thread(s) x    100000 = 3.574564&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Ruby 1.8.6 (installed with Leopard):&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_bash "&gt;$ /usr/bin/ruby main.rb &amp;quot;`/usr/bin/ruby -v`&amp;quot; 10_000_000
ruby 1.8.6 (2008-03-03 patchlevel 114) [universal-darwin9.0]
   1 thread(s) x  10000000 = 6.586917
  10 thread(s) x   1000000 = 6.78801
  50 thread(s) x    200000 = 6.951003
 100 thread(s) x    100000 = 6.907087&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Ruby 1.8.7 (installed from MacPorts):&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_bash "&gt;$ ruby main.rb   &amp;quot;`ruby -v`&amp;quot; 10_000_000
ruby 1.8.7 (2008-06-20 patchlevel 22) [i686-darwin9.4.0]
   1 thread(s) x  10000000 = 36.329174
  10 thread(s) x   1000000 = 36.808753
  50 thread(s) x    200000 = 36.715717
 100 thread(s) x    100000 = 36.499772   &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;To co niepokoi, to koszmarnie wolna praca Ruby 1.8.7 w por&#243;wnaniu do Ruby 1.8.6. To jest bardzo podejrzana sprawa. Cieszy za to dobra wydajno&#347;&#263; Ruby Enterprise.&lt;/p&gt;


	&lt;h3&gt;Python/Jython&lt;/h3&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="ident"&gt;from&lt;/span&gt; &lt;span class="ident"&gt;random&lt;/span&gt; &lt;span class="ident"&gt;import&lt;/span&gt; &lt;span class="constant"&gt;Random&lt;/span&gt;
&lt;span class="ident"&gt;from&lt;/span&gt; &lt;span class="ident"&gt;sys&lt;/span&gt; &lt;span class="ident"&gt;import&lt;/span&gt; &lt;span class="ident"&gt;argv&lt;/span&gt;
&lt;span class="ident"&gt;from&lt;/span&gt; &lt;span class="ident"&gt;time&lt;/span&gt; &lt;span class="ident"&gt;import&lt;/span&gt; &lt;span class="ident"&gt;time&lt;/span&gt;
&lt;span class="ident"&gt;from&lt;/span&gt; &lt;span class="ident"&gt;threading&lt;/span&gt; &lt;span class="ident"&gt;import&lt;/span&gt; &lt;span class="constant"&gt;Thread&lt;/span&gt;
&lt;span class="ident"&gt;rand&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Random&lt;/span&gt;&lt;span class="punct"&gt;().&lt;/span&gt;&lt;span class="ident"&gt;randint&lt;/span&gt; &lt;span class="comment"&gt;# alias&lt;/span&gt;

&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;ThreadTest(Thread):&lt;/span&gt;
   &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;__init__&lt;/span&gt; &lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;self&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;iterations&lt;/span&gt;&lt;span class="punct"&gt;):&lt;/span&gt; 
      &lt;span class="constant"&gt;Thread&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;__init__&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;self&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;              
      &lt;span class="constant"&gt;self&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;iterations&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;iterations&lt;/span&gt;
   &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;run&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;self&lt;/span&gt;&lt;span class="punct"&gt;):&lt;/span&gt; 
      &lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="ident"&gt;rand&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="number"&gt;0&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt;&lt;span class="constant"&gt;SIZE&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt; &lt;span class="keyword"&gt;for&lt;/span&gt; &lt;span class="ident"&gt;x&lt;/span&gt; &lt;span class="keyword"&gt;in&lt;/span&gt; &lt;span class="ident"&gt;xrange&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;self&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;iterations&lt;/span&gt;&lt;span class="punct"&gt;)]&lt;/span&gt;

&lt;span class="constant"&gt;SIZE&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;int&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;argv&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="number"&gt;2&lt;/span&gt;&lt;span class="punct"&gt;])&lt;/span&gt;
&lt;span class="ident"&gt;print&lt;/span&gt; &lt;span class="ident"&gt;argv&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="number"&gt;1&lt;/span&gt;&lt;span class="punct"&gt;]&lt;/span&gt;
&lt;span class="keyword"&gt;for&lt;/span&gt; &lt;span class="ident"&gt;nr&lt;/span&gt; &lt;span class="keyword"&gt;in&lt;/span&gt; &lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="number"&gt;10&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="number"&gt;50&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="number"&gt;100&lt;/span&gt;&lt;span class="punct"&gt;]:&lt;/span&gt;
  &lt;span class="ident"&gt;iterations&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;SIZE&lt;/span&gt; &lt;span class="punct"&gt;/&lt;/span&gt; &lt;span class="ident"&gt;nr&lt;/span&gt;
  &lt;span class="ident"&gt;print&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt; %3d thread(s) x %9s = &lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt; &lt;span class="punct"&gt;%&lt;/span&gt; &lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;nr&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;iterations&lt;/span&gt;&lt;span class="punct"&gt;),&lt;/span&gt;
  &lt;span class="ident"&gt;start&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;time&lt;/span&gt;&lt;span class="punct"&gt;()&lt;/span&gt;
  &lt;span class="ident"&gt;threads&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;[]&lt;/span&gt;
  &lt;span class="keyword"&gt;for&lt;/span&gt; &lt;span class="ident"&gt;i&lt;/span&gt; &lt;span class="keyword"&gt;in&lt;/span&gt; &lt;span class="ident"&gt;range&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;nr&lt;/span&gt;&lt;span class="punct"&gt;):&lt;/span&gt;
     &lt;span class="ident"&gt;t&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;ThreadTest&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;iterations&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
     &lt;span class="ident"&gt;threads&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;append&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;t&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
     &lt;span class="ident"&gt;t&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;start&lt;/span&gt;&lt;span class="punct"&gt;()&lt;/span&gt;
  &lt;span class="keyword"&gt;for&lt;/span&gt; &lt;span class="ident"&gt;t&lt;/span&gt; &lt;span class="keyword"&gt;in&lt;/span&gt; &lt;span class="ident"&gt;threads&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt;
     &lt;span class="ident"&gt;t&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;join&lt;/span&gt;&lt;span class="punct"&gt;()&lt;/span&gt;
  &lt;span class="ident"&gt;print&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;%s s.&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt; &lt;span class="punct"&gt;%&lt;/span&gt; &lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;time&lt;/span&gt;&lt;span class="punct"&gt;()&lt;/span&gt; &lt;span class="punct"&gt;-&lt;/span&gt; &lt;span class="ident"&gt;start&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt; &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Test:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_bash "&gt;$ python main.py &amp;quot;`python -V`&amp;quot; 10000000
Python 2.5.2
  1 thread(s) x  10000000 =  34.5188429356 s.
 10 thread(s) x   1000000 =  52.3496830463 s.
 50 thread(s) x    200000 =  53.9406650066 s.
100 thread(s) x    100000 =  58.3923280239 s.&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Co ciekawe, Python 2.5.2 okaza&#322; si&#281; najwolniejszy. Im wi&#281;cej w&#261;tk&#243;w tym jeszcze wolniej dzia&#322;a&#322;. By&#322; wolniejszy nawet od (dziwnie wolnego) Ruby 1.8.6. Ale, by&#263; mo&#380;e to jest wina bardzo wolnej biblioteki generowania losowych liczb. Ech, jak tu cokolwiek por&#243;wnywa&#263; mi&#281;dzy j&#281;zykami jak takie odkrywa si&#281; takie babole w bibliotece standardowej Pythona.&lt;/p&gt;


	&lt;p&gt;Jython by&#322;&#160;jeszcze wolniejszy. Dla 10 mln. iteracji, mimo &#380;e nie by&#322;y tworzone w pami&#281;ci &#380;adne listy, wl&#243;k&#322; si&#281; tak wolno, &#380;e przerwa&#322;em test. Po zmniejszeniu iteracji o rz&#261;d wielko&#347;ci (do 1 miliona) uzyska&#322; wyniki takie jak Ruby 1.8.6 dla 10 milion&#243;w iteracji. Jython jest najwyra&#378;niej jeszcze bardzo s&#322;abo zoptymalizowany. Pomys&#322;y aby na nim odpala&#263; frameworki takie jak Django, to na razie raczej przedwczesny pomys&#322;.&lt;/p&gt;


	&lt;p&gt;Iterations: 1,000,000 instead of 10,000,000:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_bash "&gt;$ jython main.py &amp;quot;`jython --version`&amp;quot; 1000000
Jython 2.2.1 on java1.6.0_05

  10 thread(s) x    100000 =  6.391000032424927 s.
  50 thread(s) x     20000 =  4.368000030517578 s.
 100 thread(s) x     10000 =  4.352999925613403 s.&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
      <pubDate>Sat, 26 Jul 2008 13:22:00 +0200</pubDate>
      <guid isPermaLink="false">urn:uuid:f3cdd08b-0fa8-4545-aa1a-8a2fcb4903ca</guid>
      <author>Jaros&#322;aw Zabie&#322;&#322;o</author>
      <link>http://blog.zabiello.com/articles/2008/07/26/threads-ruby-python</link>
      <category>ruby</category>
      <category>python</category>
      <category>jruby</category>
      <category>jython</category>
      <category>java</category>
    </item>
    <item>
      <title>Aktualizacje bezpiecze&#324;stwa dla wszystkich wersji Ruby MRI</title>
      <description>&lt;p&gt;Jak o tym pisz&#261; na &lt;a href="http://weblog.rubyonrails.org/2008/6/21/multiple-ruby-security-vulnerabilities"&gt;blogu RoR&lt;/a&gt; odkryto dosy&#263; powa&#380;ne dziury bezpiecze&#324;stwa w Ruby &lt;span class="caps"&gt;MRI&lt;/span&gt; we wszystkich wersjach od 1.8.5 do 1.9.0. Zalecana jest aktualizacja do &lt;a href="http://www.ruby-lang.org/en/news/2008/06/20/arbitrary-code-execution-vulnerabilities/"&gt;nowszych wersji&lt;/a&gt;. Problem nie dotyczy JRuby, ktory nie musi si&#281;&#160;martwi&#263;&#160;o g&#322;upie problemy z przepe&#322;nieniem bufora typowe dla j&#281;zyka C.&lt;/p&gt;


	&lt;p&gt;Nie wiem jak jest z &lt;a href="http://www.rubyenterpriseedition.com/"&gt;Ruby Enteprise&lt;/a&gt; u&#380;ywanym przez &lt;a href="http://modrails.com"&gt;Passengera&lt;/a&gt;. Profilaktycznie przestawi&#322;em aplikacj&#281; do pracy z za&#322;atanym Ruby 1.8.7-p22 (tym bardziej, &#380;e bie&#380;&#261;ca wersja Ruby Enterprise i tak nie pracuje szybciej w wypadku systemu 64-bitowego jaki u&#380;ywam na serwerze). Co ciekawe, stary Rails 1.2.3 te&#380; chodzi z nowym Ruby 1.8.7 (oficjalnie tylko Rails 2.1 jest z nim kompatybilny).&lt;/p&gt;


	&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt;&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;Ruby Enterprise (w skr&#243;cie &lt;span class="caps"&gt;REE&lt;/span&gt;) zosta&#322; dzi&#347; &lt;a href="http://blog.phusion.nl/2008/06/22/ruby-enterprise-edition-186-20080621-released/"&gt;za&#322;atany&lt;/a&gt; i dzia&#322;a w ko&#324;cu te&#380; na Mac OS-X!&lt;/li&gt;
	&lt;/ul&gt;


	&lt;ul&gt;
	&lt;li&gt;Na razie lepiej uwa&#380;a&#263; na t&#261; najnowsz&#261;, za&#322;atan&#261; wersj&#281; &lt;span class="caps"&gt;REE&lt;/span&gt;, bo jest niestabilna. Na Mac OS-X oraz na Ubuntu 7.10&amp;#215;64 wywala &amp;#8220;Segmentation fault&amp;#8221; na niekt&#243;rych stronach Rails. Wys&#322;a&#322;em ju&#380; informacj&#281; do tw&#243;rc&#243;w aby to sprawdzili.&lt;/li&gt;
	&lt;/ul&gt;</description>
      <pubDate>Sun, 22 Jun 2008 21:41:00 +0200</pubDate>
      <guid isPermaLink="false">urn:uuid:f71fe176-af23-45ab-91b9-54e13f9acce1</guid>
      <author>Jaros&#322;aw Zabie&#322;&#322;o</author>
      <link>http://blog.zabiello.com/articles/2008/06/22/ruby-dziury</link>
      <category>ruby</category>
      <category>security</category>
    </item>
    <item>
      <title>MagLev - wirtualna maszyna Smalltalka dla Rubiego</title>
      <description>&lt;p&gt;&lt;a href="http://gemstone.com"&gt;Gemstone&lt;/a&gt; to komercyjna, rozwijana od ponad 20 lat, bardzo szybka maszyna wirtualna dla j&#281;zyka &lt;a href="http://pl.wikipedia.org/wiki/Smalltalk"&gt;Smalltalk&lt;/a&gt;. Jest u&#380;ywana od  lat w zastosowaniach biznesowych, m.in. w instytucjach finansowych. W odr&#243;&#380;nieniu od innych Gemstone to co&#347; wi&#281;cej ni&#380; tylko maszyna wirtualna. Gemstone posiada wbudowany mechanizm bardzo wydajnego, transakcyjnego zapisu obiekt&#243;w, chodzi to obs&#322;ug&#281; obiekt&#243;w rz&#281;du setek i tysi&#281;cy miliard&#243;w (lub informacji o wielko&#347;ci 17 &lt;a href="http://pl.wikipedia.org/wiki/Petabajt"&gt;petabajt&#243;w&lt;/a&gt;). MagLev to smalltalkowy &lt;a href="http://www.gemstone.com/products/smalltalk/"&gt;GemStone &lt;span class="caps"&gt;S64 VM&lt;/span&gt;&lt;/a&gt; z dodanym bytecodem pozwalaj&#261;cym na uruchamianie &lt;strong&gt;Rubiego&lt;/strong&gt;. W r&#243;&#380;nych benchmarkach MagLev jest szybszy od Rubiego &lt;span class="caps"&gt;MRI&lt;/span&gt; od 7 do ponad 100 razy i osi&#261;ga &lt;a href="http://antoniocangiano.com/2008/06/05/maglev-handles-trees-like-a-monkey/"&gt;szybko&#347;&#263; zbli&#380;on&#261; do czystego C&lt;/a&gt;. Dodatkowo daje przezroczysty, wydajny zapis obiekt&#243;w Rubiego w spos&#243;b znacznie wygodniejszy od tego co oferuj&#261; relacyjne bazy danych. Czy&#380;by wkr&#243;tce mo&#380;na by&#322;o pokusi&#263; si&#281; o napisanie odpowiednika &lt;a href="http://zope.org/"&gt;Zope&lt;/a&gt; w Rubim pracuj&#261;cym pod wydajn&#261;, wirtualn&#261; maszyn&#261; Smalltalka?&lt;/p&gt;


	&lt;p&gt;Na razie projekt jest m&#322;ody. Maszyna wirtualna pewnie b&#281;dzie zamkni&#281;tym kodem, ale reszta powinna by&#263; wolna. Pierwsza prezentacja mo&#380;liwo&#347;ci Rubiego na MagLev odbyla si&#281; na niedawnej konferencji &lt;a href="http://www.infoq.com/news/2008/05/MagLevAtRailsConf"&gt;RailsConf 2008&lt;/a&gt;. Dost&#281;pne jest ju&#380; pierwsze wideo z prezentacji MagLev&amp;#8217;a (pozosta&#322;e dwie cz&#281;&#347;ci s&#261; w trakcie przygotowywania).&lt;/p&gt;


&lt;object width="400" height="302"&gt;    &lt;param name="allowfullscreen" value="true" /&gt;    &lt;param name="allowscriptaccess" value="always" /&gt;    &lt;param name="movie" value="http://www.vimeo.com/moogaloop.swf?clip_id=1147409&amp;amp;server=www.vimeo.com&amp;amp;show_title=1&amp;amp;show_byline=1&amp;amp;show_portrait=0&amp;amp;color=00ADEF&amp;amp;fullscreen=1" /&gt;    &lt;embed src="http://www.vimeo.com/moogaloop.swf?clip_id=1147409&amp;amp;server=www.vimeo.com&amp;amp;show_title=1&amp;amp;show_byline=1&amp;amp;show_portrait=0&amp;amp;color=00ADEF&amp;amp;fullscreen=1" type="application/x-shockwave-flash" allowfullscreen="true" allowscriptaccess="always" width="400" height="302"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;br /&gt;&lt;a href="http://www.vimeo.com/1147409?pg=embed&amp;#38;sec=1147409"&gt;MagLev presentation at RailsConf 2008 &amp;#8211; part 1&lt;/a&gt; from &lt;a href="http://www.vimeo.com/montywilliams?pg=embed&amp;#38;sec=1147409"&gt;Monty Williams&lt;/a&gt; on &lt;a href="http://vimeo.com?pg=embed&amp;#38;sec=1147409"&gt;Vimeo&lt;/a&gt;.

	&lt;p&gt;&lt;br /&gt;&lt;/p&gt;


	&lt;p&gt;Zobacz te&#380;:&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;&lt;a href="http://www.infoq.com/news/2008/04/maglev-gemstone-builds-ruby"&gt;MagLev: Gemstone builds Ruby runtime based on Smalltalk VM&lt;/a&gt;&lt;/li&gt;
	&lt;/ul&gt;


	&lt;ul&gt;
	&lt;li&gt;&lt;a href="http://www.infoq.com/interviews/bryant-ruby-maglev-gemstone"&gt;Avi Bryant on MagLev and GemStone&lt;/a&gt; &amp;#8211; b. ciekawy wywiad (video + transkrypcja)&lt;/li&gt;
	&lt;/ul&gt;


	&lt;ul&gt;
	&lt;li&gt;&lt;a href="http://www.infoq.com/news/2008/05/MagLevAtRailsConf"&gt;GemStone Reveals Plans for MagLev Ruby VM at RailsConf 2008&lt;/a&gt;&lt;/li&gt;
	&lt;/ul&gt;


	&lt;ul&gt;
	&lt;li&gt;&lt;a href="http://antoniocangiano.com/2008/06/05/maglev-handles-trees-like-a-monkey/"&gt;MagLev handles trees like a monkey&lt;/a&gt;&lt;/li&gt;
	&lt;/ul&gt;


	&lt;ul&gt;
	&lt;li&gt;&lt;a href="http://www.avibryant.com/?p=16"&gt;Avi Bryant &amp;#8211; MagLev recap&lt;/a&gt;&lt;/li&gt;
	&lt;/ul&gt;


	&lt;ul&gt;
	&lt;li&gt;&lt;a href="http://antoniocangiano.com/2008/05/31/maglev-rocks/"&gt;MagLev rocks and the planning of the next Ruby shootout&lt;/a&gt;&lt;/li&gt;
	&lt;/ul&gt;


	&lt;ul&gt;
	&lt;li&gt;&lt;a href="http://collison.ie/blog/2008/06/maglev-and-language-implementation"&gt;MagLev and language implementation&lt;/a&gt;&lt;/li&gt;
	&lt;/ul&gt;


	&lt;ul&gt;
	&lt;li&gt;&lt;a href="http://railsconf.blip.tv/file/568689/"&gt;RailsConf 2007 &amp;#8211; Avi Bryant&lt;/a&gt; &amp;#8211; ciekawe wyst&#261;pienie Avi Branta przekonanego &#380;e zasadniczo Ruby prawie nie r&#243;&#380;ni si&#281; od Smalltalka, w zasadzie to ten sam j&#281;zyk i nie ma &#380;adnego powodu dla kt&#243;rego Ruby nie m&#243;g&#322;by by&#263; tak szybki jak Smalltalk (a Smalltalk jest 10x szybszy od Pythona&amp;#8230;)&lt;/li&gt;
	&lt;/ul&gt;


	&lt;ul&gt;
	&lt;li&gt;&lt;a href="http://www.chadfowler.com/2008/6/5/maglev"&gt;Chad Fowler &amp;#8211; MagLev&lt;/a&gt;&lt;/li&gt;
	&lt;/ul&gt;</description>
      <pubDate>Sat, 14 Jun 2008 19:11:00 +0200</pubDate>
      <guid isPermaLink="false">urn:uuid:7408024c-7849-459e-b285-3e78c4c33579</guid>
      <author>Jaros&#322;aw Zabie&#322;&#322;o</author>
      <link>http://blog.zabiello.com/articles/2008/06/14/maglev</link>
      <category>smalltalk</category>
      <category>ruby</category>
      <category>maglev</category>
      <category>rails</category>
      <category>vm</category>
      <category>gemstone</category>
    </item>
    <item>
      <title>Passenger bli&#380;ej - Rails, Rack i WSGI</title>
      <description>&lt;p&gt;Stworzony pierwotnie na u&#380;ytek Rails, aktualnie mod_passenger ju&#380; obs&#322;uguje nie tylko Rails ale tak&#380;e mas&#281; innych framework&#243;w u&#380;ywaj&#261;cych Rack&amp;#8217;a. W &lt;a href="http://tinyurl.com/6edmve"&gt;nowej dokumentacji&lt;/a&gt; wymienione s&#261; frameworki: &lt;a href="http://code.whytheluckystiff.net/camping"&gt;Camping&lt;/a&gt;, &lt;a href="http://halcyon.rubyforge.org/"&gt;Halcyon&lt;/a&gt;, &lt;a href="http://www.mackframework.com/"&gt;Mack&lt;/a&gt;, &lt;a href="http://merbivore.org/"&gt;Merb&lt;/a&gt;, &lt;a href="http://ramaze.net/"&gt;Ramaze&lt;/a&gt; i &lt;a href="http://sinatrarb.com/Home"&gt;Sinatra&lt;/a&gt;. W dokumentacji nie wymieniono jeszcze &amp;#8220;drugiej listy&amp;#8221;, zawieraj&#261;cej frameworki korzystaj&#261;ce z &lt;a href="http://www.wsgi.org/wsgi"&gt;&lt;span class="caps"&gt;WSGI&lt;/span&gt;&lt;/a&gt; i Pythona (np. &lt;a href="http://pylonshq.com/"&gt;Pylons&lt;/a&gt;, &lt;a href="http://djangoproject.com"&gt;Django&lt;/a&gt;, &lt;a href="http://turbogears.org/"&gt;TurboGears&lt;/a&gt; itp.). Chc&#261;c sprawdzi&#263; plotki wok&#243;&#322; tej sprawy, sprawdzi&#322;em, czy faktycznie mod_passenger pracuje nie tylko z Ruby, ale tak&#380;e z Pythonem. Sprawdzi&#322;em tak&#380;e jak to jest faktycznie z ob&#322;ug&#261; Rails i framework&#243;w na Rack&amp;#8217;u (tu sprawdzi&#322;em tylko Merba). Sprawdzi&#322;em te&#380; JRuby dla Rails i Merba.&lt;/p&gt;


	&lt;p&gt;Wszystkie testy by&#322;y wykonywane na laptopie MacBook Pro Core 2 Duo, 2.16GHZ, 4GB &lt;span class="caps"&gt;RAM&lt;/span&gt; (OSX 10.5.3 dla tego modelu widzi tylko 3GB) i dyskiem 200GB kr&#281;c&#261;cym si&#281; z szybko&#347;ci&#261; 7200 rpm. Ruby 1.8.6, Python 2.5.2, Apache 2.2.8 (mpm-prefork) by&#322;y instalowane z MacPort&#243;w. Passenger, mimo &#380;e instalowany &lt;a href="http://github.com/FooBarWidget/passenger/tree/master"&gt;ze &#378;r&#243;de&#322;&lt;/a&gt; w Apache&amp;#8217;u by&#322; wy&#347;wietlany jako &amp;#8220;Phusion_Passenger/1.1.0&amp;#8221; (by&#263; mo&#380;e wi&#281;c to nie jest jeszcze ta nowa wersja 2.0 o kt&#243;rej pisa&#322;em &lt;a href="http://blog.zabiello.com/articles/2008/06/04/passenger2-ruby-enterprise"&gt;wcze&#347;niej&lt;/a&gt;) Nie sprawdza&#322;em Linuksa, by&#263; mo&#380;e wyniki i wnioski b&#281;d&#261; wtedy inne.&lt;/p&gt;


	&lt;p&gt;Dla tych co chcieliby sami popr&#243;bowa&#263; podaj&#281; wpierw konfiguracj&#281; serwer&#243;w wirtualnych dla Apache&amp;#8217;a potrafi&#261;c&#261; unie&#347;&#263; razem: &lt;span class="caps"&gt;PHP&lt;/span&gt; (2.5.6), Rails (2.1), Merb (0.9.4 edge), i Django (edge).&lt;/p&gt;


	&lt;h2&gt;Konfiguracja Apache&amp;#8217;a  2.2.8&lt;/h2&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_apache "&gt;
# Ruby (Rails):
&amp;lt;VirtualHost *:80&amp;gt;     
  DocumentRoot &amp;quot;/opt/local/apache2/vhosts/rails_app/public&amp;quot;  
  ServerName rails_app
&amp;lt;/VirtualHost&amp;gt;

# Ruby (Merb):        
&amp;lt;VirtualHost *:80&amp;gt;  
  RailsAutoDetect off  
  DocumentRoot &amp;quot;/opt/local/apache2/vhosts/merb_app/public&amp;quot;    
  ServerName merb_app       
&amp;lt;/VirtualHost&amp;gt;

# Python (WSGI):
&amp;lt;VirtualHost *:80&amp;gt;          
  DocumentRoot &amp;quot;/opt/local/apache2/vhosts/wsgi_app/public&amp;quot;    
  ServerName wsgi_app
&amp;lt;/VirtualHost&amp;gt;      

# Django (mod_python)
&amp;lt;VirtualHost *:80&amp;gt;         
  DocumentRoot &amp;quot;/opt/local/apache2/vhosts/djangus/public&amp;quot;    
  ServerName django_modpython 
  &amp;lt;Location &amp;quot;/&amp;quot;&amp;gt;
    SetHandler python-program
    PythonHandler django.core.handlers.modpython
    SetEnv DJANGO_SETTINGS_MODULE djangus.settings
    PythonDebug On        
    PythonPath &amp;quot;['/opt/local/apache2/vhosts'] + sys.path&amp;quot;    
  &amp;lt;/Location&amp;gt;       
&amp;lt;/VirtualHost&amp;gt;   

# PHP:
&amp;lt;VirtualHost *:80&amp;gt;  
  RailsAutoDetect off  
  DocumentRoot &amp;quot;/opt/local/apache2/vhosts/php_app/public&amp;quot;        
  ServerName php_app   
&amp;lt;/VirtualHost&amp;gt;    &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Wszystkie aplikacje korzystaj&#261;ce z mod_passengera musz&#261; posiada&#263; folder &lt;code&gt;public&lt;/code&gt; i &lt;code&gt;tmp&lt;/code&gt;. Gdy do katalogu &lt;code&gt;tmp&lt;/code&gt; dorzucimy jakikolwiek (mo&#380;e by&#263; pusty) plik o nazwie &lt;code&gt;restart.txt&lt;/code&gt;, to przy nast&#281;pnym prze&#322;adowaniu przegl&#261;darki nast&#261;pi restart aplikacji.&lt;/p&gt;


	&lt;p&gt;We wszystkich przypadkach u&#380;y&#322;em dosy&#263; banalnego kodu polegaj&#261;cego na wy&#347;wietleniu &amp;#8220;Hello World!&amp;#8221;. Z wynik&#243;w programu &lt;code&gt;ab&lt;/code&gt; wyci&#261;&#322;em nieistotne informacje.&lt;/p&gt;


	&lt;h2&gt;Rails (2.1)&lt;/h2&gt;


	&lt;h3&gt;Rails 2.1 + mod_passenger 1.1.0&lt;/h3&gt;


	&lt;p&gt;Rails obs&#322;ugiwane s&#261; w Passengerze praktycznie bezobs&#322;ugowo. Wystarczy wkopiowa&#263; pliki na serwer i to wszystko.&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_bash "&gt;ab -n 1000 -c 1 http://rails/ 
...
Concurrency Level:      1
Failed requests:        0
Write errors:           0
Total transferred:      582000 bytes
HTML transferred:       12000 bytes
Requests per second:    430.20 [#/sec] (mean)
Transfer rate:          244.35 [Kbytes/sec] received

ab -n 1000 -c 4 http://rails/
...
Concurrency Level:      4
Failed requests:        239
   (Connect: 0, Length: 239, Exceptions: 0)
Write errors:           0
Total transferred:      488073 bytes
HTML transferred:       9132 bytes
Requests per second:    520.75 [#/sec] (mean)
Transfer rate:          247.88 [Kbytes/sec] received&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 

	&lt;p&gt;Szybko&#347;&#263; nie jest najgorsza, ale niepokoj&#261;ca jest du&#380;a lista b&#322;&#281;dnych request&#243;w w wypadku zapyta&#324; r&#243;wnoleg&#322;ych. Jak si&#281; dalej okazuje, ten problem dotyczy tak&#380;e ob&#322;ugi Rack jak i &lt;span class="caps"&gt;WSGI&lt;/span&gt;. Albo to jaka&#347; specyfika &lt;span class="caps"&gt;OSX&lt;/span&gt;, albo wcale nie jest tak dobrze ze stabilno&#347;ci&#261; mod_passengera dla r&#243;wnoleg&#322;ych zapyta&#324;. Trzeba by by&#322;o te&#380; zbada&#263;, czy ten efekt wyst&#281;puje tak&#380;e dla Linuksa. Zdziwi&#322;bym si&#281; gdyby tam by&#322;o podobnie skoro Dreamhost ju&#380; oferuje hosting z mod_rails&amp;#8230;&lt;/p&gt;


	&lt;p&gt;Dla por&#243;wnania Rails u&#380;ywaj&#261;cy Mongrela, Thin oraz Ebb. Mo&#380;na by pokusi&#263; aby odpali&#263; Ebb i Thina na uniksowych socketach (Ebb te&#380; to ju&#380; potrafi!), ale wtedy musia&#322;bym zestawia&#263; klaster i uruchamia&#263; to przez proxy. Jak kto&#347; chce to niech si&#281; sam pobawi. Dla prostoty u&#380;y&#322;em port&#243;w &lt;span class="caps"&gt;TCP&lt;/span&gt;. Sprawdzi&#322;em te&#380; JRuby.&lt;/p&gt;


	&lt;h3&gt;Rails 2.1 + Ebb 0.2.0&lt;/h3&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_bash "&gt;ebb_rails -e production start

ab -n 1000 -c 1 http://127.0.0.1:3000/
...
Concurrency Level:      1
Failed requests:        0
Write errors:           0
Requests per second:    488.95 [#/sec] (mean)

ab -n 1000 -c 4 http://127.0.0.1:3000/
..
Concurrency Level:      4
Failed requests:        0
Write errors:           0
Requests per second:    533.22 [#/sec] (mean)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt; 

	&lt;p&gt;Szybko&#347;&#263; wi&#281;ksza od mod_passengera i co wa&#380;niejsze, zero jakichkolwiek b&#322;&#281;d&#243;w przy pracy r&#243;wnoleg&#322;ej.&lt;/p&gt;


	&lt;h3&gt;Rails 2.1 + Thin 0.8.1&lt;/h3&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_bash "&gt;thin start -e production              

ab -n 1000 -c 1 http://127.0.0.1:3000/
...
Concurrency Level:      1
Failed requests:        0
Write errors:           0
Requests per second:    485.95 [#/sec] (mean)

ab -n 1000 -c 4 http://127.0.0.1:3000/
...              
Concurrency Level:      4
Failed requests:        0
Write errors:           0
Requests per second:    506.21 [#/sec] (mean)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Szybko&#347;&#263; troch&#281; mniejsza od Ebb, ale stabilno&#347;&#263; b. dobra.&lt;/p&gt;


	&lt;h3&gt;Rails 2.1 + Mongrel 1.1.5&lt;/h3&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_bash "&gt;script/server -e production

ab -n 1000 -c 1 http://127.0.0.1:3000/
...
Concurrency Level:      1
Failed requests:        0
Write errors:           0
Requests per second:    373.74 [#/sec] (mean)

ab -n 1000 -c 4 http://127.0.0.1:3000/
...
Concurrency Level:      4
Failed requests:        0
Write errors:           0
Requests per second:    360.46 [#/sec] (mean)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Stabilno&#347;&#263; bez zarzutu, wydajno&#347;&#263; jednak mniejsza od serwer&#243;w pracuj&#261;cych asynchronicznie.&lt;/p&gt;


	&lt;h3&gt;Rails 2.1 + JRuby 1.1.2&lt;/h3&gt;


	&lt;p&gt;W wypadku JRuby trzeba go troch&#281; &amp;#8220;rozgrza&#263;&amp;#8221;. Pe&#322;na wydajno&#347;&#263; Javy pojawia si&#281; po jakim&#347; czasie pracy. Wynika to ze specyfiki i mo&#380;liwo&#347;&#263;i &lt;span class="caps"&gt;JVM&lt;/span&gt; kt&#243;ra dokonuje dynamicznych optymalizacji kodu w trakcie jego dzia&#322;ania (z tego powodu Java potrafi przewy&#380;szy&#263; wydajno&#347;ci&#261; C++). &amp;#8220;Dla rozgrzewki&amp;#8221; przepu&#347;ci&#322;em Rails przez 30 tys. request&#243;w co spowodowa&#322;o &#380;e pocz&#261;tkowych 137 req/s zrobi&#322;o si&#281; 257 req/s.&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_bash "&gt;jruby script/server -e production    

ab -n 1000 -c 1 http://127.0.0.1:3000/
...
Concurrency Level:      1
Failed requests:        0
Write errors:           0
Requests per second:    200.48 [#/sec] (mean)

ab -n 1000 -c 4 http://127.0.0.1:3000/
...
Concurrency Level:      4
Failed requests:        0
Write errors:           0
Requests per second:    257.05 [#/sec] (mean)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;JRuby jest stabilny ale z wydajno&#347;ci&#261; dla Rails jeszcze jest troch&#281; do poprawienia. Dorzucenie opcji optymalizacyjnych, czyli odpalenie Rails przez&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_bash "&gt;  
jruby -J-server -J-Djruby.compile.frameless=true script/server -e production&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;troch&#281; poprawi&#322;o wynik: 273 req/s, ale generalnie nie jest to wielka r&#243;&#380;nica. JRuby 1.1.x ju&#380; ma domy&#347;lnie pow&#322;&#261;czane optymalizacje.&lt;/p&gt;


	&lt;h3&gt;Rails &amp;#8211; wnioski&lt;/h3&gt;


	&lt;p&gt;mod_passenger dla Rails faktycznie jest wydajny, cho&#263; trzeba jeszcze by zbada&#263; dlaczego zwraca tyle b&#322;&#281;dnych request&#243;w dla r&#243;wnoleg&#322;ych zapyta&#324; i czy ten problem wyst&#281;puje te&#380; na Linuksie. Dlatego na razie najwydajniejszym i najstabilniejszym rozwi&#261;zaniem dla Rails wci&#261;&#380; pozostaje kombinacja nginx + proxy do ebb lub thin. mod_passenger kusi g&#322;&#243;wnie prostot&#261; konfiguracji (w&#322;a&#347;ciwie brakiem konfiguracji). No i chyba ja to testowa&#322;em dla mod_passengera w wersji 1.1, a nie 2.0 (przynajmniej taka si&#281; wy&#347;wietla w Apache).&lt;/p&gt;


	&lt;h2&gt;Merb 0.9.4 edge&lt;/h2&gt;


	&lt;h3&gt;Merb 0.9.4 edge + mod_passenger 1.1.0&lt;/h3&gt;


	&lt;p&gt;Aby u&#380;y&#263; frameworka Rack z Passengerem trzeba w katalogu projektu tworzy&#263; plik &lt;code&gt;config.ru&lt;/code&gt; zawieraj&#261;cy konfiguracj&#281; Rack&amp;#8217;a. W wypadku Merba b&#281;dzie to&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="ident"&gt;require&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;rubygems&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;
&lt;span class="ident"&gt;require&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;merb-core&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;

&lt;span class="constant"&gt;Merb&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;Config&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;setup&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="symbol"&gt;:merb_root&lt;/span&gt;   &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;.&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;,&lt;/span&gt;
                   &lt;span class="symbol"&gt;:environment&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="constant"&gt;ENV&lt;/span&gt;&lt;span class="punct"&gt;['&lt;/span&gt;&lt;span class="string"&gt;RACK_ENV&lt;/span&gt;&lt;span class="punct"&gt;'])&lt;/span&gt;
&lt;span class="constant"&gt;Merb&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;environment&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Merb&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;Config&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="symbol"&gt;:environment&lt;/span&gt;&lt;span class="punct"&gt;]&lt;/span&gt;
&lt;span class="constant"&gt;Merb&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;root&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Merb&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;Config&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="symbol"&gt;:merb_root&lt;/span&gt;&lt;span class="punct"&gt;]&lt;/span&gt;
&lt;span class="constant"&gt;Merb&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;BootLoader&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;run&lt;/span&gt;

&lt;span class="ident"&gt;run&lt;/span&gt; &lt;span class="constant"&gt;Merb&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;Rack&lt;/span&gt;&lt;span class="punct"&gt;::&lt;/span&gt;&lt;span class="constant"&gt;Application&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;  &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_bash "&gt;Concurrency Level:      1
Failed requests:        0
Write errors:           0
Requests per second:    762.62 [#/sec] (mean)

Concurrency Level:      4
Failed requests:        247
   (Connect: 0, Length: 247, Exceptions: 0)
Write errors:           0
Requests per second:    985.15 [#/sec] (mean) &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Merb jest wci&#261;&#380; du&#380;o szybszy od Rails. Podobnie jak dla Rails, wiele r&#243;wnoleg&#322;ych zapyta&#324; nie zosta&#322;o poprawnie wykonanych. Na produkcyjne u&#380;ycie Passengera dla Merba jest jeszcze troch&#281; za wcze&#347;nie.&lt;/p&gt;


	&lt;h3&gt;Merb 0.9.4 edge + ebb 0.2.0&lt;/h3&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_bash "&gt;merb -e production -a ebb  
...                              
Concurrency Level:      4
Failed requests:        0
Write errors:           0
Requests per second:    1463.69 [#/sec] (mean)

Concurrency Level:      10
Failed requests:        0
Write errors:           0
Requests per second:    1560.60 [#/sec] (mean)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;  

	&lt;p&gt;Merb na Ebb deklasuje wydajno&#347;ci&#261; wszystkie inne rozwi&#261;zania. Tylko czysty &lt;span class="caps"&gt;PHP&lt;/span&gt; jest w stanie mu dor&#243;wna&#263;, ale por&#243;wnywanie &lt;span class="caps"&gt;PHP&lt;/span&gt; z ca&#322;ym, z&#322;o&#380;onym frameworkiem Rubiego jest troch&#281; bez sensu. Z tego co m&#243;wi&#322; ostatnio (na kanale &lt;span class="caps"&gt;IRC&lt;/span&gt;) Ezra Zygmuntowicz, podpi&#281;cie Ebb na czystym Rack&amp;#8217;u, daje nawet &lt;strong&gt;7 tys req/s&lt;/strong&gt; i deklasuje (rzekomo) szybkiego &lt;span class="caps"&gt;PHP&lt;/span&gt;. Gadanie o wy&#380;szej wydajno&#347;ci &lt;span class="caps"&gt;PHP&lt;/span&gt; jest po prostu g&#322;upie. Mo&#380;na si&#281; za&#322;o&#380;y&#263;, &#380;e jakiekolwiek por&#243;wnanie frameworka naprzeciw frameworka, tj. Merba z Symfony czy Cake &lt;span class="caps"&gt;PHP&lt;/span&gt;, obna&#380;y bezlito&#347;nie s&#322;abo&#347;ci &lt;span class="caps"&gt;PHP&lt;/span&gt; &lt;a href="http://blog.zabiello.com/articles/2006/07/14/django-i-rails-bij%C4%85-php"&gt;tak, jak to zrobi&#322; Django&lt;/a&gt; w jednym ze starszych test&#243;w.&lt;/p&gt;


	&lt;h3&gt;Merb 0.9.4 edge + thin 0.8.1&lt;/h3&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_bash "&gt;merb -e production -a thin 
...
Concurrency Level:      1
Failed requests:        0
Write errors:           0
Requests per second:    1147.78 [#/sec] (mean)

Concurrency Level:      4
Failed requests:        0
Write errors:           0
Requests per second:    1234.82 [#/sec] (mean)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;  

	&lt;p&gt;Wydajno&#347;&#263; r&#243;wnie dobra, cho&#263; troch&#281; s&#322;absza od Ebb. Sporo wi&#281;cej od Rails i zero problem&#243;w ze stabilno&#347;ci&#261;.&lt;/p&gt;


	&lt;h3&gt;Merb 0.9.4 edge + mongrel 1.1.5&lt;/h3&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_bash "&gt;merb -e production -a mongrel
...
Concurrency Level:      1
Failed requests:        0
Write errors:           0
Requests per second:    868.10 [#/sec] (mean)

Concurrency Level:      4
Failed requests:        0
Write errors:           0
Requests per second:    837.01 [#/sec] (mean)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;   

	&lt;p&gt;Mongrel jest wolniejszy od serwer&#243;w asynchronicznych ale i tak wyra&#378;nie szybszy od Rails.&lt;/p&gt;


	&lt;h3&gt;Merb 0.9.4 edge + JRuby 1.1.2&lt;/h3&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_bash "&gt; 
jruby -S merb -e production 
...
Concurrency Level:      1
Failed requests:        0
Write errors:           0
Requests per second:    449.52 [#/sec] (mean)

Concurrency Level:      4
Failed requests:        0
Write errors:           0
Requests per second:    505.52 [#/sec] (mean)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Merb na &amp;#8220;rozgrzanym&amp;#8221; (30 tys. req) JRuby osi&#261;ga wydajno&#347;&#263; tak&#261; jak najszybsze rozwi&#261;zania dla Rails z u&#380;yciem asynchronicznego Ebb! To znaczy, &#380;e u&#380;ycie produkcyjne Merba w systemach Javy ma jak najbardziej sens.&lt;/p&gt;


	&lt;h2&gt;Passenger &amp;#38; &lt;span class="caps"&gt;WSGI&lt;/span&gt;&lt;/h2&gt;


	&lt;p&gt;Pora na przyjrzenie si&#281; temu jak mod_passenger daje sobie rad&#281; z Pythonem. W katalogu ze &#378;r&#243;d&#322;ami Passengera le&#380;y gotowa, prosta aplikacja &lt;span class="caps"&gt;WSGI&lt;/span&gt;. Dzieki dobrej dokumentacji Django, uda&#322;o mi si&#281; uruchomi&#263; ten framework pod Passengerem. Gorzej by&#322;o z Pylons. Nie uda&#322;o mi si&#281; stworzy&#263; poprawnego pliku passenger_wsgi.py, niezb&#281;dnego do tego aby Passenger uruchomi&#322; aplikacj&#281; &lt;span class="caps"&gt;WSGI&lt;/span&gt;.&lt;/p&gt;


	&lt;h3&gt;Django edge&lt;/h3&gt;


	&lt;p&gt;Django, mimo swych zalet, stosuje bardzo g&#322;upi&#261; polityk&#281; nie wypuszczania kolejnych wersji kodu. Dost&#281;pna na stronie wersa 0.96 jest stara i generalnie zaleca si&#281; aby u&#380;ywa&#263; nowsz&#261; wersj&#281;, kt&#243;ra istnieje tylko w repozytorium Subversion. Oparcie kodu produkcyjnego o wersj&#281; edge jest troch&#281; ryzykowne i szybko sprowadza si&#281; do z&#322;ej praktyki ci&#261;g&#322;ego  &#322;atania kodu.&lt;/p&gt;


	&lt;p&gt;W wypadku Django plik &lt;code&gt;passenger_wsgi.py&lt;/code&gt; zawiera kod:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="ident"&gt;import&lt;/span&gt; &lt;span class="ident"&gt;os&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;sys&lt;/span&gt;
&lt;span class="ident"&gt;sys&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;path&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;append&lt;/span&gt;&lt;span class="punct"&gt;('&lt;/span&gt;&lt;span class="string"&gt;/bezwl/sciezka/do/nazwaprojektu&lt;/span&gt;&lt;span class="punct"&gt;')&lt;/span&gt; 
&lt;span class="ident"&gt;os&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;environ&lt;/span&gt;&lt;span class="punct"&gt;['&lt;/span&gt;&lt;span class="string"&gt;DJANGO_SETTINGS_MODULE&lt;/span&gt;&lt;span class="punct"&gt;']&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;nazwaprojektu.settings&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;
&lt;span class="ident"&gt;import&lt;/span&gt; &lt;span class="ident"&gt;django&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;core&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;handlers&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;wsgi&lt;/span&gt;
&lt;span class="ident"&gt;application&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;django&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;core&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;handlers&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;wsgi&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;WSGIHandler&lt;/span&gt;&lt;span class="punct"&gt;()&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_bash "&gt;  ab -n 10000 -c 10            
  ...   
  apr_poll: The timeout specified has expired (70007)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Test pad&#322; po 9tys requestach. Dalej nie mo&#380;na by&#322;o uruchomi&#263; Django. Dopiero restart calego Apache&amp;#8217;a pom&#243;g&#322;. Dla ni&#380;szej ilo&#347;ci r&#243;wnoleg&#322;ych zapyta&#324; (ab -n 1000 -c 4) Django nie pad&#322;o, ale by&#322;o du&#380;o b&#322;&#281;dnych request&#243;w. Okaza&#322;o si&#281;, &#380;e problem wynika&#322; z r&#243;wnoczesnej obecno&#347;ci modu&#322;u mod_python i mod_passenger. Nie mo&#380;na ich razem w&#322;&#261;cza&#263;.&lt;/p&gt;


	&lt;p&gt;Usuni&#281;cie mod_passengera i zostawienie samego mod_pythona pomog&#322;o. (Albo jest jaki&#347; konflikt mi&#281;dzy nimi, albo (co bardziej jest prawdopodobne) trzeba poczeka&#263; na opcj&#281; wy&#322;&#261;czaj&#261;c&#261; passengera dla serwera wirtualnego u&#380;ywaj&#261;cego mod_pythona. Dla Rails i Rack s&#261; takie opcje (RailsAutoDetect, RackAutoDetect), dla &lt;span class="caps"&gt;WSGI&lt;/span&gt; nie mog&#322;em nic takiego znale&#378;&#263; w kodzie &#378;r&#243;d&#322;owym. Modu&#322;u mod_wsgi nie sprawdza&#322;em, bo nie by&#322;o go dost&#281;pnego w portach &lt;span class="caps"&gt;OSX&lt;/span&gt;.)&lt;/p&gt;


	&lt;p&gt;Po zablokowaniu mod_passenger&amp;#8217;a tym razem mod_python nie zwraca&#322; &#380;adnego b&#322;&#281;dnego requestu.&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_bash "&gt;Concurrency Level:      1
Failed requests:        0
Write errors:           0
Requests per second:    934.87 [#/sec] (mean)

Concurrency Level:      4
Failed requests:        0
Write errors:           0
Requests per second:    1240.26 [#/sec] (mean)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Nie jest &#378;le. Django jest tu wyra&#378;nie szybsze od Rails (co nikogo nie dziwi), ale jest wolniejsze od Merba, co dla mi&#322;o&#347;nik&#243;w Pythona mo&#380;e by&#263; przykr&#261; niespodziank&#261;. Wi&#281;kszo&#347;&#263; krytyki Rubiego oparta jest na krytyce (s&#322;abszej) wydajno&#347;ci Rails&#243;w. Okazuje si&#281;, &#380;e winny nie jest Ruby, ale s&#322;abo zoptymalizowany Rails. Merb jest dowodem na to, &#380;e mo&#380;na napisa&#263; w Rubim framework, kt&#243;ry nie tylko b&#281;dzie partnerem dla rozwi&#261;zan Pythona, ale nawet potrafi je przewy&#380;sza&#263; wydajno&#347;ciowo.&lt;/p&gt;


	&lt;p&gt;Zobaczmy jak wypadnie &lt;strong&gt;mod_passenger&lt;/strong&gt;.&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_bash "&gt;Concurrency Level:      1
Failed requests:        0
Write errors:           0
Requests per second:    904.60 [#/sec] (mean)

Concurrency Level:      4
Failed requests:        240
   (Connect: 0, Length: 240, Exceptions: 0)
Write errors:           0
Requests per second:    497.51 [#/sec] (mean)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;W pracy jednoprocesowej nie mo&#380;na mie&#263; zastrze&#380;e&#324;. Szybko&#347;&#263; jest niez&#322;a. Niestety praca r&#243;wnoleg&#322;a to pora&#380;ka. Du&#380;o request&#243;w nie zosta&#322;o obs&#322;u&#380;onych. Gorzej, za drugim razem (tylko dla 4 rownoleg&#322;ych zapyta&#324;) Django kompletnie si&#281; za&#322;ama&#322;o i zwr&#243;ci&#322;o wyj&#261;tek &amp;#8220;apr_poll: The timeout specified has expired (70007)&amp;#8221;. Nie mo&#380;na by&#322;o go d&#322;u&#380;ej u&#380;ywa&#263;. Wymagany by&#322; restart Apache&amp;#8217;a.&lt;/p&gt;


	&lt;p&gt;Aby sprawdzi&#263; czy to tylko problem Django czy og&#243;lnie implementacji &lt;span class="caps"&gt;WSGI&lt;/span&gt; dla mod_passengera, uruchomi&#322;em test na prostej aplikacji &lt;span class="caps"&gt;WSGI&lt;/span&gt;. Niestety sytuacja jest ta sama.&lt;/p&gt;


	&lt;p&gt;&lt;strong&gt;Wniosek&lt;/strong&gt;: mod_passenger dla Pythona wymaga dopracowania pracy r&#243;wnoleg&#322;ej. Jeszcze za wcze&#347;nie aby go u&#380;ywa&#263; z Pythonem. Ale z drugiej strony uruchomi&#322;em mod_passengera z &lt;span class="caps"&gt;WSGI&lt;/span&gt;  troch&#281; przedwcze&#347;nie. Nie ma przecie&#380; w manualu ani jednego zdania o tym, &#380;e Passenger dzia&#322;a z &lt;span class="caps"&gt;WSGI&lt;/span&gt;. Opar&#322;em si&#281; tylko na pog&#322;oskach i wygrzeba&#322;em t&#261; opcj&#281; ze &#378;r&#243;de&#322;. Wi&#281;c jeszcze wszystko mo&#380;e si&#281; tu zmieni&#263;. To samo dotyczy Rack&amp;#8217;a. Tw&#243;rcy musz&#261; przyjrze&#263; si&#281; problemom zwi&#261;zanym z obs&#322;ug&#261; r&#243;wnoleg&#322;ych zapyta&#324;.&lt;/p&gt;


	&lt;h3&gt;Update&lt;/h3&gt;


	&lt;p&gt;Jednak dobrze si&#281; domy&#347;la&#322;em, Apache nie oszukiwa&#322;. W tek&#347;cie testowa&#322;em starszego Passengera 1.1. Tak&#380;e nie by&#322; to Ruby Enterprise. &lt;span class="caps"&gt;NOWY&lt;/span&gt; Passenger 2.0RC1 oraz Ruby Enterprise zosta&#322; dopiero niedawno &lt;a href="http://blog.phusion.nl/2008/06/09/phusion-passenger-20-rc-1-and-ruby-enterprise-edition-released/"&gt;opublikowany&lt;/a&gt;. Co ciekawe, dodano obs&#322;ug&#281; Apache &lt;span class="caps"&gt;MPM&lt;/span&gt; &lt;strong&gt;Worker&lt;/strong&gt; a nie &lt;span class="caps"&gt;MPM&lt;/span&gt; Prefork, co dodatkowo zmniejsza zu&#380;ycie pami&#281;ci. Niestety Passenger 2.0RC1 jest na razie dost&#281;pny tylko w wersji na Linuksa.&lt;/p&gt;</description>
      <pubDate>Sat, 07 Jun 2008 15:24:00 +0200</pubDate>
      <guid isPermaLink="false">urn:uuid:1dc84c82-1634-41dd-9aa1-9c744a876dff</guid>
      <author>Jaros&#322;aw Zabie&#322;&#322;o</author>
      <link>http://blog.zabiello.com/articles/2008/06/07/passenger-rack-wsgi</link>
      <category>rails</category>
      <category>ruby</category>
      <category>python</category>
      <category>django</category>
      <category>merb</category>
      <category>apache</category>
      <category>benchmark</category>
      <category>jruby</category>
    </item>
    <item>
      <title>Sprz&#261;tanie po PHP czyli Passenger 2.0 i Ruby Enterprise 1.0</title>
      <description>&lt;p&gt;Sta&#322;o si&#281;! &lt;a href="http://www.phusion.nl/"&gt;Tw&#243;rcy&lt;/a&gt; &#347;wietnego modu&#322;u Apache&amp;#8217;a &amp;#8211; &lt;a href="http://www.modrails.com/"&gt;mod_rails&lt;/a&gt; &amp;#8211; zmieniaj&#261; jego nazw&#281; na &lt;strong&gt;mod_passenger&lt;/strong&gt;, bo mod_rails nie jest ju&#380; wi&#281;cej modu&#322;em tylko dla &lt;a href="http://rubyonrails.pl"&gt;Rails&lt;/a&gt;. W nowej wersji 2.0 (ktora ma wyj&#347;&#263;&#160;&lt;a href="http://groups.google.com/group/phusion-passenger/browse_thread/thread/a2b63650c1b9394"&gt;na dniach&lt;/a&gt;) dodano pe&#322;ne wsparcie dla &lt;a href="http://blog.zabiello.com/articles/2008/03/04/frameworki-rubiego-rack-wsgi"&gt;Rack&lt;/a&gt; i tym samym mod_passenger 2.0 obs&#322;uguje wszystkie pozosta&#322;e frameworki u&#380;ywaj&#261;ce Rack&amp;#8217;a (ze &#347;wietnym &lt;a href="http://merbivore.com"&gt;Merbem&lt;/a&gt; w&#322;&#261;cznie).&lt;/p&gt;


	&lt;p&gt;Drugim, ciekawym projektem firmy &lt;a href="http://www.phusion.nl/"&gt;Phusion&lt;/a&gt; jest &lt;a href="http://www.rubyenterpriseedition.com/"&gt;Ruby Enterprise&lt;/a&gt; (wersja 1.0 ma by&#263; dost&#281;pna lada dzie&#324; razem z Passenger 2.0). Jest to podrasowana wersja interpretera Rubiego (MRI) powoduj&#261;ca nie tylko przy&#347;pieszenie ale tak&#380;e znaczne zmniejszenie zu&#380;ycia pami&#281;ci &lt;span class="caps"&gt;RAM&lt;/span&gt; (dodano technik&#281; copy-on-write do garbage collectora interpretera &lt;span class="caps"&gt;MRI&lt;/span&gt;, dok&#322;adniej opisano to na &lt;a href="https://dl.getdropbox.com/u/26205/railsconf.pdf"&gt;slajdach&lt;/a&gt;). Wg tego co twierdz&#261; ludzie z Phusion, uzyskano zmniejszenie o 33% zu&#380;ycia pami&#281;ci przez Rails. To bardzo dobra wiadomo&#347;&#263;, bo pami&#281;&#263; mimo, &#380;e jest generalnie tania, nie jest tania w ofertach hostingowych &lt;span class="caps"&gt;VPS&lt;/span&gt;.&lt;/p&gt;


	&lt;p&gt;Passenger wprowadza now&#261; jako&#347;&#263; dla framework&#243;w Rubiego. Coraz wi&#281;cej firm hostingowych to docenia i przechodzi na Passenger&amp;#8217;a (z tych bardziej znanych, &lt;a href="http://blog.dreamhost.com/2008/05/13/passenger-for-ruby-on-rails/"&gt;Dreamhost ju&#380; tego u&#380;ywa&lt;/a&gt;). Sam modu&#322;&#160;mod_passenger jest nie tylko trywialny w u&#380;yciu, jest te&#380; bardzo szybki i stabilny. Chyba nadchodz&#261; ci&#281;&#380;kie chwile dla tych, co trzymali si&#281; &lt;span class="caps"&gt;PHP&lt;/span&gt; g&#322;&#243;wnie z powodu jego taniego hostingu i prostoty uruchomiania serwerze. Rails i Merb mog&#261; wkr&#243;tce troch&#281; pozamiata&#263; po &lt;span class="caps"&gt;PHP&lt;/span&gt;. :)&lt;/p&gt;


	&lt;p&gt;Szybko&#347;&#263; mod_passenger&amp;#8217;a robi wra&#380;enie. Bije wydajno&#347;ci&#261; kombinacj&#281; &lt;a href="http://nginx.net/"&gt;Nginx&lt;/a&gt; + asynchroniczny &lt;a href="http://code.macournoyer.com/thin/"&gt;Thin&lt;/a&gt; u&#380;ywaj&#261;cy szybkich, uniksowych socket&#243;w. Jest te&#380; szybszy od komercyjnego &lt;a href="http://litespeedtech.com/"&gt;Litespeed&amp;#8217;a&lt;/a&gt;.&lt;/p&gt;


	&lt;p&gt;&lt;img src="http://blog.zabiello.com/images/passenger_vs_thin.png" alt="" /&gt;&lt;/p&gt;


	&lt;p&gt;&lt;img src="http://blog.zabiello.com/images/passenger_vs_litespeed.png" alt="" /&gt;&lt;/p&gt;


	&lt;p&gt;Co ciekawe, mod_passenger obs&#322;uguje interfejs &lt;strong&gt;&lt;span class="caps"&gt;WSGI&lt;/span&gt; do Pythona&lt;/strong&gt;! Jeden modu&#322; pozwoli wi&#281;c na odpalanie Rails, Merb&amp;#8217;a i Django r&#243;wnocze&#347;nie. Ma&#322;o tego, je&#347;li mod_passenger dla Pythona b&#281;dzie dzia&#322;a&#322; tak sprawnie jak dla Rails, to b&#281;dziemy mie&#263; trywialne prze&#322;adowywanie aplikacji Django bez konieczno&#347;ci restartu ca&#322;ego Apache&amp;#8217;a.&lt;/p&gt;


	&lt;p&gt;Vide:&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;&lt;a href="http://www.railsjedi.com/posts/52-The-Holy-Grail-for-Rails-Deployment"&gt;The Holy Grail for Rails Deployment&lt;/a&gt;&lt;/li&gt;
	&lt;/ul&gt;


	&lt;ul&gt;
	&lt;li&gt;&lt;a href="http://www.rubyinside.com/28_mod_rails_and_passenger_resources-899.html"&gt;28 mod_rails / Passenger Resources To Help You Deploy Rails Applications Faster&lt;/a&gt;&lt;/li&gt;
	&lt;/ul&gt;


	&lt;ul&gt;
	&lt;li&gt;&lt;a href="http://github.com/FooBarWidget/passenger/tree/master"&gt;Passenger 2.0 na GitHub.com&lt;/a&gt; dla tych, co chc&#261; ju&#380; teraz zainstalowa&#263; mod_passenger 2.0 (ja ju&#380; to zainstalowa&#322;em)&lt;/li&gt;
	&lt;/ul&gt;


	&lt;h3&gt;Update&lt;/h3&gt;


	&lt;p&gt;&lt;em&gt;2008-06-25&lt;/em&gt;&lt;/p&gt;


&lt;object width="400" height="225"&gt;    &lt;param name="allowfullscreen" value="true" /&gt;    &lt;param name="allowscriptaccess" value="always" /&gt;    &lt;param name="movie" value="http://www.vimeo.com/moogaloop.swf?clip_id=1198020&amp;amp;server=www.vimeo.com&amp;amp;show_title=1&amp;amp;show_byline=1&amp;amp;show_portrait=0&amp;amp;color=&amp;amp;fullscreen=1" /&gt;    &lt;embed src="http://www.vimeo.com/moogaloop.swf?clip_id=1198020&amp;amp;server=www.vimeo.com&amp;amp;show_title=1&amp;amp;show_byline=1&amp;amp;show_portrait=0&amp;amp;color=&amp;amp;fullscreen=1" type="application/x-shockwave-flash" allowfullscreen="true" allowscriptaccess="always" width="400" height="225"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;br /&gt;&lt;a href="http://www.vimeo.com/1198020?pg=embed&amp;#38;sec=1198020"&gt;Phusion Passenger 2.0 and Ruby Enterprise Edition&lt;/a&gt; from &lt;a href="http://www.vimeo.com/user519957?pg=embed&amp;#38;sec=1198020"&gt;Carl Youngblood&lt;/a&gt; on &lt;a href="http://vimeo.com?pg=embed&amp;#38;sec=1198020"&gt;Vimeo&lt;/a&gt;

	&lt;ul&gt;
	&lt;li&gt;&lt;a href="http://blog.dmilith.pl/2008/06/25/ruby-enterprise-edition-32bit-na-debianie-etch-64bit"&gt;Ruby Enterprise Edition 32bit na debianie etch 64bit?&lt;/a&gt;&lt;/li&gt;
	&lt;/ul&gt;</description>
      <pubDate>Wed, 04 Jun 2008 01:40:00 +0200</pubDate>
      <guid isPermaLink="false">urn:uuid:77d6b3df-2b86-4365-b5de-d4fd9b153ecc</guid>
      <author>Jaros&#322;aw Zabie&#322;&#322;o</author>
      <link>http://blog.zabiello.com/articles/2008/06/04/passenger2-ruby-enterprise</link>
      <category>mod_rails</category>
      <category>ruby</category>
      <category>rails</category>
      <category>merb</category>
      <category>rack</category>
      <category>apache</category>
      <category>php</category>
      <category>django</category>
      <category>python</category>
    </item>
    <item>
      <title>Ruby on Rails w Irlandii</title>
      <description>&lt;p&gt;Tak pomy&#347;la&#322;em, &#380;e mo&#380;e wrzuc&#281; info tutaj, bo troch&#281; os&#243;b z bran&#380;y czyta ten blog. Ot&#243;&#380; w mojej firmie szukamy &lt;a href="http://www.rubyonrails.pl/forum/viewtopic.php?pid=5546#p5546"&gt;jakiego&#347; railsowca do zespo&#322;u&lt;/a&gt;.&lt;/p&gt;</description>
      <pubDate>Thu, 29 May 2008 21:21:00 +0200</pubDate>
      <guid isPermaLink="false">urn:uuid:0d50f135-226a-4690-9cc8-bd144dee6026</guid>
      <author>Jaros&#322;aw Zabie&#322;&#322;o</author>
      <link>http://blog.zabiello.com/articles/2008/05/29/ruby-on-rails-w-irlandii</link>
      <category>rails</category>
      <category>ruby</category>
      <category>ireland</category>
      <category>praca</category>
    </item>
  </channel>
</rss>
