piątek, 24 sierpnia 2007

Producent-Konsument w Javie 5

Całkiem niedawno, przeglądając dokumentację API dla Java 1.5, odkryłem że pojawił się tam całkiem ciekawy mechanizm upraszczający rozwiązanie odwiecznego problemu Producenta - Konsumenta.

Interfejs BlockingQueue, bo o nim mowa, reprezentuje typ synchronizowanej kolejki o zadanej pojemności. Udostępnia bardzo wygodne w użyciu metody wstawiania (add / offer / put) i pobierania obiektów (poll / take). Ich wygoda polega na ich różnorodności:
  • put wstawia obiekt, czekając jeśli trzeba na zwolnienie miejsca w kolejce
  • offer próbuje wstawić obiekt i zwraca true / false jako odpowiedź czy operacja się udała
  • add wstawia obiekt do kolejki "na siłę" i ewentualnie rzuca IllegalStateException jeśli kolejka jest już pełna
  • take pobiera obiekt z kolejki, czekając jeśli trzeba na pojawienie się obiektu w kolejce
  • poll pobiera obiekt z kolejki lub null, jeśli upłynie określona ilość czasu a kolejka jest pusta
Korzystając z powyższych metod, przykładowa implementacja klas producenta i konsumenta może wyglądać tak (wg oficjalnej dokumentacją Javy):

class Producer implements Runnable {
private final BlockingQueue queue;

Producer(BlockingQueue q) { queue = q; }

public void run() {
try {
while(true) { queue.put(produce()); }
} catch (InterruptedException ex) { ... }
}

Object produce() { ... }
}

class Consumer implements Runnable {
private final BlockingQueue queue;

Consumer(BlockingQueue q) { queue = q; }

public void run() {
try {
while(true) { consume(queue.take()); }
} catch (InterruptedException ex) { ... }
}

void consume(Object x) { ... }
}

piątek, 10 sierpnia 2007

Przygoda w świecie kamieni szlachetnych

Być może udało mi się niektórych spośród czytelników tego bloga przekonać do zapoznania z Ruby. Ale jak zacząć? Cóż, ponieważ chodzi o Ruby, to musi być trywialne! I rzeczywiście jest.

Zdecydowanie najprostszym sposobem na wypróbowanie możliwości Ruby jest Ruby w przeglądarce. Doskonałe rozwiązanie na początek, nie wymagające żadnej ingerencji we własny system. Dodatkowym atutem tej strony jest krótki, interaktywny kurs języka.

Jeśli już zdecydujemy się na instalację Ruby, to również nie będzie z tym problemu. Gotowe do instalacji pakiety są dla większości dystrybucji Linuxa, a instalatory dla MacOS X (One-Click Installer, Locomotive czy przez MacPorts) oraz Windows (oficjalna binarna wersja Ruby lub One-Click Installer z wieloma dodatkowymi bibliotekami).

Na tym jednak nie kończą się możliwości. Można również zacząć używać Ruby, nie przesiadając się ze środowiska Javy czy .NET, dzięki projektom JRuby i IronRuby. Gwarantują one pełny dostęp do VM tych środowisk i płynne współdziałanie kodu pisanego w innych językach razem z Ruby.

Podsumowując, nie ma powodu żeby przynajmniej nie spróbować przygody z Ruby!

piątek, 3 sierpnia 2007

Społeczność i nastawienie

Zapewne większość tych, którzy stykają się ze społecznością Ruby jest wręcz onieśmielona entuzjazmem, z jakim ludzie odpowiadają na ich pytania (czy to na Ruby Forum, czy na IRC, czy na grupie comp.lang.ruby).

Ponieważ jednak nie każdy ma ochotę / czas / odwagę spróbować swoją przygodę z Ruby (do czego oczywiście zachęcam!), to dla przykładu kilka cytatów z zaledwie paru dni (od 1. do 3. sierpnia) na Ruby-Talk:
  • "many thanks for the quick response and the valuable hint" - Ralph Grothe
  • "WOW! What a reply! This has got to be the single best thing for Ruby - the peeps on this mailing list are awesome!" - Gabriel Dragffy
  • "quick reply (didn't last a minute)" - Shai Rosenfeld
  • "Thanks a million!" - John Joyce
  • "That is exactly what I have been looking for" - Henrik Kristiansen
  • "Holy Cow! You guys are geniuses! Y'all are using these methods like I've never seen or even thought of using them before." - Todd Burch
Zwykle pierwsza odpowiedź pojawia się w ciągu godziny, a nawet trywialne pytania potrafią rozwinąć się w dyskusje o alternatywnych rozwiązaniach. Dodam też, że sam Yukihiro Matsumoto (twórca języka Ruby) pojawia się tu i ówdzie udzielając bardzo cennych rad.

Czego można chcieć więcej?

czwartek, 2 sierpnia 2007

Ruby potęgą jest i basta!

Pisanie w języku Ruby może być miłą odmianą po codziennej używaniu języków o statycznej kontroli typów. To oczywiście subiektywna opinia, ale może uda mi się, szanowny Czytelniku, przekonać chociaż do zapoznania się z możliwościami, jakie daje Ruby.

Oto konkretny przykład. Potrzebny nam był w pracy niewielki skrypt, który miał zaktualizować adresy e-mail użytkowników wg określonego klucza. Razem z kolegą usiadłem więc do JEdit i po chwili 64-liniowy skrypcik Ruby był gotowy. Otwierał połączenie z Oracle, odczytywał dane z blisko 60 tys. kont, przerabiał e-mail dla tych, które spełniały określone kryteria, po czym zapisywał z powrotem do bazy danych. Po drodze tworzył plik z opisem zmian i wypluwał na ekran kilka komunikatów.

Nic nadzwyczajnego, prawda? Dlatego byliśmy mocno zdziwieni, kiedy skrypt po uruchomieniu zamarł. Zjadł 90% czasu procesora i... to tyle. Po przerwaniu jego męczarni, dopisaniu jeszcze kilku tekstów o postępie działania i ponownym uruchomieniu okazało się, że wbrew pozorom coś robi, tylko strasznie wolno. Kilka minut później skrypt zakończył działanie, pozostawiając bazę we właściwym stanie, mnie mocno zaniepokojonego, a kolegę zniesmaczonego. Miałem co prawda podejrzanego:

if emails.include? row[1]
...
else
emails << row[1]
end

gdzie "emails" to tablica (Array). Czyżby metody "include?" oraz "<<" na tablicy 60 tys. elementów się nie sprawdzały? Odpowiedź przyszła dzień później. Na grupie comp.lang.ruby ktoś pytał czy istnieje metoda "not-include?". Jak to zwykle na c.l.r dostał dużo odpowiedzi ("unless" zamiast "if", "if not", "if !"). Między innymi, Brett Simmers zasugerował użycie Set zamiast Array, jeśli istotne jest tylko czy dany element znajduje się w zbiorze. I to było to!

W moim skrypcie niezbędne były zaledwie te zmiany:
  1. require 'set' (Set jest w standardowych bibliotekach Ruby)
  2. emails = Set.new (zamiast emails = Array.new)
Po ich wprowadzeniu i ponownym uruchomieniu, skrypt wykonał się w kilkanaście sekund.

Jaki z tego morał? Imponująca jest elastyczność kodu pisanego w Ruby, w którym wprowadzanie zmian nie musi powodować konieczności pisania od nowa całych jego fragmentów. A wartość dodana, jaką stanowi społeczność Ruby, jest przysłowiową wisienką na torcie.

Tak, dobrze widzisz. To kolejny blog w Internecie

Na każdym zebraniu jest taka sytuacja, że ktoś musi zacząć pierwszy
- Rejs

...i właśnie dlatego pojawia się ten post. Każdy blog jakoś się zaczyna i ten nie będzie wyjątkiem.

Tematyka tego bloga jest jasno określona - sztuka tworzenia oprogramowania. Postaram się pisać tylko o tym, co uznam za warte uwagi.

Skąd wziął się tytuł "Nie tylko młotek"? Jest krótką wersją motto tego bloga: "Kiedy masz pod ręką tylko młotek, wszystko dookoła wygląda jak gwóźdź". A co to niby ma znaczyć? Tylko i aż tyle, że ograniczanie sobie dostępnych narzędzi może znacząco utrudnić rozwiązywanie problemów.

Jeśli "młotkowo-narzędziowe" przedstawienie tematyki bloga Tobie nie odpowiada, to może spróbuj odpowiedzieć sobie na pytanie dlaczego systemów operacyjnych nie pisze się w Javie? Albo dlaczego serwerów WWW nie pisze się w assemblerze? Kiedy już odpowiesz sobie na takie pytania, zrozumiesz o czym jest ten blog :-)