Perl vs reszta świata cz. I
Autor: Marcin Guzowski | Data:
28.05.2007, 23:25
| Kategorie: Świat Perla
| Komentarze (0)
| Ślady (0)
Od długich lat trwają w różnych środowiskach ożywione dyskusje na temat zalet i wad poszczególnych języków programowania. Naturalnie dywagacje tego typu dotyczą także Perla (o dziwo najczęściej prowadzą je programiści Pythona, którzy wiecznie poszukują uzasadnienia, że Python jest lepszy od Perla :) ). Nie zamierzam tutaj analizować pojawiających się argumentów, skupie się jedynie na zestawie subiektywnie wybranych aspektów, których omówienie może dostarczyć postronnemu czytelnikowi pewnych praktycznych wskazówek.
Zastosowania Programiści Perla oczywiście powiedzą, że Perl nadaje się do wszelakich zastosowań. Trzeba przyznać, że stwierdzenie to jest całkiem bliskie prawdzie. Nie oznacza to jednak, że język ten sprawi się równie dobrze w każdym scenariuszu. Według mnie, Perl stanowi dobry wybór do masowego przetwarzania danych (także w modelu współbieżnym i rozproszonym), czynności administracyjnych (głównie pod systemami Unix/Linux), wszelkich operacji na plikach, komunikacji sieciowej, aplikacji webowych (mod_perl), aplikacji serwerowych. Nie używałbym natomiast Perla do budowy aplikacji desktopowych (napisanych np. w Perl/Tk), choć widziałem już udane projekty tego typu. Po prostu inne technologie sprawdzą się w tym zadaniu lepiej - m.in. ze względy na szybszy i łatwiejszy proces produkcji. Nie jest prawdą, że w Perlu nie można programować obiektowo. Otóż z powodzeniem można, ale OOP stanowi tylko swoiste rozszerzenie tego języka i nie wynika z jego założeń, jak w przypadku choćby C#. Perl został stworzony jako wolne oprogramowanie pod systemy unixowe, ale od dawna dostępny jest także na inne platformy - Win32 (jest też wersja x64), Mac OS czy Solaris. Odpowiednio napisany kod, w który zrezygnujemy z elementów platform-specific, będzie więc bardzo łatwo przenaszalny. W Perlu obserwuje się ostatnio dynamiczny rozwój skrzydła Win32 - i rzeczywiście trzeba przyznać, że interpreter działa na Win32 zarówno stabilne (w skali Windowsa), jak i niewiele mniej wydajne niż w przypadku systemów spod znaku pingwina. Istotną siłę Perla stanowi bogactwo dostępnych modułów zgromadzonych w CPAN (Comprehensive Perl Archive Network, http://cpan.org). Programowanie w Perlu sprowadza się więc najczęściej do umiejętności wyszukiwania i wykorzystywania poszczególnych modułów, gdyż na 90% ktoś napisał już to, co jest nam potrzebne :) Co więcej - napisał to nieźle. Akurat pod względem ilości dostępnych bibliotek z Perlem nie może się równać żaden inny język skryptowy, a jest to na pewno jedna z tych cech, które powinny mieć spory udział w decyzji o zastosowaniu konkretnego języka programowania. Składnia Składnia Perla jest jedną z tych cech, która czyni ten język bardzo specyficznym, bywa też często krytykowana. Podnoszony jest m.in. argument, że przez możliwość zapisania takiego samego polecenia na szereg różniących się i mało intuicyjnych sposobów kod traci na przejrzystości. Z drugiej strony składnia Perla daje deweloperom swobodę kreowania kodu według własnych potrzeb i umiejętności. Istotnie, dla przeciętnego programisty losowy fragment kodu napisany w Perlu będzie trudniejszy do zrozumienia niż w przypadku C#, Javy czy Pythona. Powiem więcej, składnia Perla wręcz zachęca do pisania trudnego w utrzymywaniu kodu, którego później nie zrozumie nawet jego twórca. Nie oznacza to jednak, że w Perlu nie można pisać porządnie - otóż można. Krytyka języka (zwłaszcza ze strony amatorów języków bardzo przejrzystych składniowo - np. Pythona) opiera się na założeniu, że każdy programista jest niechlujem i prędzej czy później pójdzie na totalną łatwiznę na zasadzie "byle działało". Rzeczywiście, jeżeli mamy takich programistów w zespole, to Perlem zrobią krzywdę i sobie i projektowi. Jeżeli natomiast będziemy trzymali się wcale znowu nie trudnych do wdrożenia zasad, pisali kod w ustalony sposób, z komentarzami itp. - na pewno nie ma się o co obawiać. Perl jest trudniejszy w opanowaniu niż inne języki z Pythonem na czele - ale nie ma nic za darmo. Wolność musi mieć swoją cenę, a nie jest ona znowu jakoś przesadnie wysoka. Wiele konstrukcji i koncepcji językowych, jak choćby domyślne zmienne, są właściwe praktycznie wyłącznie Perlowi. Krytyka tego typu rozwiązań jest jak najbardziej dopuszczalna - każdy może mieć swoje zdanie. Nie jest dopuszczalne natomiast podawanie nieprawdy za argument na poparcie swych tez. Wiele razy widziałem już tendencyjne porównania składni, gdzie podana była implementacja prostej operacji w kilku językach. Najczęściej kod reprezentujący Perla napisany był w jakiś zupełnie kosmiczny i dysfunkcjonalny sposób, podczas gdy istniała zupełnie standardowa konstrukcja realizująca określone zadanie. Przykładowo: ktoś dowodził, że w Perlu w ogóle nie da się w prosty sposób kontrolować ilości parametrów przekazanych do metody (zapisał więc szereg warunków sprawdzających istnienie poszczególnych parametrów), nie mając widać w ogóle pojęcia o możliwości zastosowania zmiennej tablicowej @_. Szybkość działania Oczywiście generalne porównywanie szybkości działania aplikacji napisanych w różnych językach ma taki sam sens, jak dyskusja o wyższości jednych świąt nad innymi. Wszystko zależy przecież od przeznaczenia aplikacji, jej architektury wewnętrznej, platformy sprzętowej itd. Perl jest językiem interpretowanym, aplikacje napisane w tym języku najczęściej nie występują więc w formie skompilowanej do kodu maszynowego, a w formie kodu źródłowego (skrypty) lub kodu pośredniego (bytecodu). Dwie z ostatnio wymienionych form wymagają istnienia w systemie operacyjnym zainstalowanego interpretera. Kompilacja skryptu Perla do kodu maszynowego jest jak najbardziej możliwa, ale trzeba pamiętać, że odbywa się w specyficzny sposób. Kompilowany jest tak na prawdę kod C z osadzonym kodem Perla (często zaszyfrowanym) oraz całym interpreterem i potrzebnymi modułami w postaci bibliotek ładowanych dynamiczne. Podczas działania takiego skompilowanego programu następuje pełne rozpakowanie kodu Perla do pamięci, a następnie oddanie go pod kontrolę interpretera. Model taki jest więc podatny na wszelkie próby reverse engineeringu w dużo większym stopniu, niż np. skompilowana aplikacja C/C++. Koncepcja ta jest w założeniach podobna do wirtualnej maszyny Javy i zapewnia analogiczne bezpieczeństwo kodu oraz co do zasady podobną wydajność działania aplikacji. Wszystko więc tak na prawdę zależy od tego, jak szybko interpreter Perla (czyli perl - pisany z małej litery) wykonuje określonego typu operacje. A niektóre z nich wykonuje tak samo wydajnie albo nawet wydajniej, niż skompilowana do kodu maszynowego aplikacja C. Należą do nich m.in. operacje na tekście (zaawansowane wyrażenia regularne), niektóre operacje na strukturach danych oraz na plikach. Perl ma jeszcze jedną zaletę, krytyczne fragmenty kodu mogą być zaimplementowane w czystym C za pomocą modułu Inline::C, dowolne funkcje C mogą być także wywoływane za pomocą interfejsu PerlXS. Wymienione sposoby otwierają Perla na bardzo bliską współpracę z C i nie powinno to dziwić - interpreter Perla (perl) jest bowiem programem C. Odpowiednio napisana aplikacja Perla może więc być tak samo szybka, jak natywna aplikacja C. Pomysł polega na tym, że zaimplementowanie niektórych funkcjonalności w Perlu zajmuje kilka razy mniej czasu niż w przypadku pisania wydajnego kodu C (a tak właśnie jest w większości przypadków, do których Perl został namaszczony). Mamy więc taką samą szybkość działania aplikacji, której stworzenie zajęło kilka razy mniej czasu. Implementowanie skomplikowanych algorytmów wykorzystujących wyrażenia regularne w C stanowiłoby w pewnym sensie ponowne odkrywanie Ameryki, gdyż podobne zadania zostały już porządnie przemyślane i wykonane w interpreterze Perla. Powyższe dywagacje powinny uzmysłowić, że umiejętnie wykorzystanie Perla może dać bardzo pozytywne efekty w kwestii wydajności. Nawiasem mówiąc, swego czasu robiłem pewne testy porównawcze między Perlem i C# w klasycznym scenariuszu deduplikacji danych (kliknij tutaj). Program w Perlu okazał się ok. 50% szybszy od swojego odpowiednika w C#, przy bardziej zaawansowanym algorytmie różnica szybkości byłaby pewnie znacznie większa. To be continued... DBD::ODBC, SQL Server i unicode
Autor: Marcin Guzowski | Data:
06.04.2007, 18:35
| Kategorie: Świat Perla, MS SQL Server
| Komentarze (0)
| Ślady (0)
W przypadku pobierania danych unikodowych z SQL Server (kolumny typu nchar, nvarchar i ntext) do aplikacji Perl na Win32 (ActivePerl 5.8.x) za pomocą DBI przez ODBC (moduł DBD::ODBC w wersji 1.13) tracone są wszystkie znaki nie mieszczące się w kodowaniu Latin-*. Problem nie jest może nowy, ale jego rozwiązania może być kłopotliwe - dlatego postanowiłem o nim napisać.
DBI na DBD::ODBC błędne interpretuje typy danych nchar, nvarchar, ntext - w związku z czym zmienne skalarne, do których trafiają dane unikodowe, nie mają ustawionej flagi utf8 i w logice interpretera nie są poprawnymi unikodowymi łańcuchami znaków. Przykładowo: tekst w cyrylicy zostanie zapisany do pamięci programu jako ciąg znaków zapytania w ASCII (??????) i tak też Perl będzie go przetwarzał. W przypadku innych modułów DBD (np. DBD::ADO) lub innych providerów (np. Win32::SqlServer) problem nie występuje lub możliwe jest dokonanie ustawień, które go wyeliminują. Moduł DBD::ODBC z różnych powodów w praktyce nie jest już rozwijany, dlatego nie warto liczyć na nową wersję, w której poprawione zostaną wyżej opisane problemy. Do wersji 1.13 istnieje nieoficjalny patch, który wprowadza do modułu prawidłową obsługę danych unikodowych pobieranych z niektórych baz danych - w tym SQL Server 2000 i 2005. Do zastosowania patcha wymagana jest ręczna rekompilacja DBD::ODBC. Instalację patcha zalecam wykonać w następujący sposób: 1. Najpierw należy pobrać kod modułu z CPAN (link poniżej lub plik do pobrania stąd). 2. Następnie rozpakowujemy archiwum (zostanie utworzony katalog DBD-ODBC-1.13, w którym przeprowadzimy dalsze czynności). 3. Jeżeli moduł DBD::ODBC jest obecnie zainstalowany, zalecane jest jego usunięcie. W konsolowej wersji PPM najpierw szukamy wpisu modułu za pomocą polecenia query, a następnie usuwamy za pomocą komendy remove. 4. Następnie pobieramy plik z kodem patchującym (link poniżej lub plik do pobrania stąd) i wrzucamy go do rozpakowanego w pkt 2 katalogu. 5. Uruchamiamy polecenie (możliwość wykonywania którego w środowisku Windows trzeba zapewnić sobie samemu przez zainstalowanie pakietu narzędzi unixowych np. UnxUtils - link poniżej): patch -p1 < unicode-patch.txt 6. Następnie przystępujemy do standardowej ręcznej kompilacji modułu. Zakładam, że w systemie zainstalowane jest SDK i jakaś wersja kompilatora C/C++ (choćby darmowa - Visual C++ Express), dostępne jest więc też narzędzie nmake. Kompilację najlepiej przeprowadzić z linii komend IDE/kompilatora (np. Visual Studio 2005 Command Prompt), wtedy nie będzie problemu ze ścieżkami i zmiennymi środowiskowymi. Upraszczając, kompilacja polega na kolejnym uruchomieniu następujących komend: perl Makefile.pl Jeżeli wszystko przebiegnie prawidłowo, to w pkt 5 zostanie zainstalowany i podpięty spachowany moduł DBD::ODBC, który prawidłowo obsłuży dane unikodowe pobierane z SQL Server. Czasem trzeba trochę powalczyć podczas kompilacji, ale najczęściej odbywa się ona bez większych problemów. Więcej informacji i pobieranie: CPAN: DBD-ODBC-1.13 DBD::ODBC-1.13 Unicode Patch UnxUtils homepage Visual C++ Express Download: .NET Framework 2.0 Software Development Kit (SDK) (x86) Przetwarzanie wyrażeń logicznych
Autor: Marcin Guzowski | Data:
11.02.2007, 15:02
| Kategorie: Świat Perla, MS SQL Server, Platforma .NET, Różne
| Komentarze (0)
| Ślady (0)
Ogromna większość technologii programistycznych (języków programowania, języków skryptowych itp.) zakłada specyficzny sposób przetwarzania wyrażeń logicznych zawartych najczęściej w różnego typu instrukcjach warunkowych (IF, WHILE, FOR). Chodzi o to, że zdanie logiczne składające się z kilku wyrażeń, np:
A OR B OR C jest uwzględniane tylko do momentu, w którym da się określić wartość całego wyrażenia. W powyższym przykładzie moment ten nastąpi już w sytuacji, w której wartość logiczna wyrażenia A będzie prawdziwa (alternatywa jest prawdziwa, gdy prawdziwy jest jeden z jej elementów). Głównym uzasadnieniem takiej obsługi są kwestie wydajnościowe i praktyczne. Opisane podejście do przetwarzania warunków ma jednak szereg konsekwencji, które warto sobie uświadomić. Postaram się zwrócić na nie uwagę bardziej szczegółowo prezentując implementację zasygnalizowanego zagadnienia w kilku środowiskach. Practical Extraction and Report Language (Perl) Spójrzmy na poniższy skrypt: #!/usr/bin/perl Interesuje nas odpowiedź na pytanie, czy funkcja func() zostanie w ogóle wywołana. Otóż - zgodnie z tym, co napisałem we wstępie - nie zostanie. Nie ma potrzeby sprawdzania wyrażenia z funkcją, gdyż już na podstawie nieprawdziwości wyrażenia $a != 1 (1 != 1) można stwierdzić, że całe zdanie warunku jest fałszywe. Skrypt drukuje więc: 0 Trzeba o tym pamiętać umieszczając funkcję w logice instrukcji warunkowych. W rzeczywistości to właśnie opisana obsługa warunków umożliwia stosowanie konstrukcji typu: if (defined $zmienna and $zmienna == 5) { } Gdyby za każdym razem przetwarzane było całe wyrażenie, to przy zastosowanym use warnings; dochodziłoby do monitu: Use of uninitialized value in numeric eq (==) at (...) zawsze wtedy, kiedy $zmienna byłaby undef. Platforma .NET (C#) Obsługa jest analogiczna, poniższy program drukuje 0. using System; Podobnie jak w Perlu, w C# (i innych językach .NETowskich) dzięki specyficznej obsłudze wyrażeń logicznych możliwe jest stosowanie konstrukcji: if (obj != null && obj.property == 2) { } Różnica między C# i Perlem polega jednak w tym przypadku na tym, że o ile w Perlu użycie niezainicjalizowanej zmiennej skutkuje co najwyżej ostrzeżeniem (warning level), o tyle w .NET użycie nieistniejącego obiektu kończy się rzuceniem wyjątku NullReferenceException(). C/C++ Przykładowy kod w przypadku C: #include < stdio.h> Jeżeli w powyższym kodzie pierwsze wyrażenie składowe warunku IF zostanie zmienione na 1 == 1, to większość kompilatorów w ogóle nie uwzględni drugiego wyrażenia alternatywy (z funkcją func()) - skompiluje więc warunek jako zawsze prawdziwy. Można się o tym łatwo przekonać zamieniając dodatkowo nazwę funkcji w warunku na taką, która nie istnieje: if (1 == 1 || nie_mam_definicji(&count) == 2) { } W obu przypadkach (zmieniony i niezmieniony kod przykładowy) skompilowany program zwraca 0. JavaScript Obsługa jest analogiczna: <SCRIPT TYPE="text/javascript"> Alert prezentuje wartość 0. Microsoft SQL Server Jeżeli wywołamy poniższy T-SQL: SELECT 0/0 SQL Server natychmiast rzuci błędem: Msg 8134, Level 16, State 1, Line 1 Kiedy jednak dzielenie przez 0 znajdzie się w odpowiednim warunku logicznym: IF (1=1 OR 1=0/0) błąd nie występuje, gdyż nie dochodzi do wykonania wadliwego kodu. O ile w przypadku Perla, C czy C# specyficzna ewaluacja warunków logicznych jest czymś pozytywnym, o tyle w świecie baz danych prowadzi do pewnych niekonsekwencji. Trzeba pamiętać, że SQL Server i inne RDBMS implementują logikę trójwartościową (three-valued logic, 3VL). Przestrzeń nie ogranicza się więc do wartości TRUE i FALSE, lecz składa się na nią TRUE, FALSE i UNKNOWN. Może więc dojść do sytuacji, że kiedy - ze względu na operację z NULLem - warunek powinien mieć wartość logiczną UNKNOWN, w praktyce zwraca wartość prawdy. Dokładnie taka sytuacja ma miejsce w poniższym przykładzie: DECLARE @a int; Warto o tym pamiętać, gdyż NULLe i stany nieokreśloności mogą generować sporą ilość trudno wykrywalnych problemów. Sposób ewaluacji wyrażeń logicznych jest analogiczny w stosunku do wyżej opisanego w przypadku wszystkich znanych mi technologii (języków). Wiedza o takim sposobie obsługi jest więc całkiem wskazana tym bardziej, że umożliwi ona zapisywanie skomplikowanych warunków logicznych w sposób bardziej wydajny - czyli taki, aby sterując kolejnością wyrażeń składowych jak najwcześniej dało się zaprzeczyć lub uznać za prawdziwy cały warunek. Oczywiście ten swoisty tuning wyrażeń logicznych może mieć miejsce wyłącznie w środowisku, które respektuje kolejność wykonywania wyrażeń składowych zgodnie z ich występowaniem w kodzie (od lewej do prawej). Jest to powszechny standard, ale np. SQL Server się do niego nie stosuje. Goodbye POE
Autor: Marcin Guzowski | Data:
21.01.2007, 23:35
| Kategorie: Świat Perla
| Komentarze (0)
| Ślady (0)
Cytując dokumentację (link poniżej): POE, czyli Perl Object Environment to opensourcowe narzędzie-środowisko do szybkiego tworzenia wielozadaniowych aplikacji sieciowych. Autorzy wymieniają szereg cech, które mają zachęcić do tworzenia rozwiązań w tym frameworku - m.in. szerokie wsparcie dla komunikacji sieciowej, wygodny silnik obsługi zdarzeń, mechanizm kolejkowania komunikatów czy możliwości programowania rozproszonego. POE ma być także remedium na odwieczne problemy związane z wielowątkowością i wieloprocesowością.
Wszystko wygląda niezwykle obiecująco, szczerze mówiąc - trochę zbyt obiecująco. Za wyżej wymienionym wachlarzem funkcjonalności nie podąża jednak popularność POE. Swego czasu na grupie pl.comp.lang.perl (link poniżej) odbyła się krótka dyskusja na temat tego środowiska. Ludzie podkreślali, że POE jest zbyt skomplikowane i te same algorytmy można implementować w dużo prostszy sposób. O ile poziom skomplikowania nie jest argumentem najistotniejszym przy wyborze technologii - liczą się przecież możliwości, o tyle istnienie prostszego alternatywnego sposobu na osiąganie tych samych funkcjonalności może już stanowić czynnik dyskwalifikujący. POE zacząłem się przyglądać przy okazji poszukiwań technologii, w której mogą być wykonane różne aplikacje przetwarzające duże ilości danych. W grę wchodzi więc zarówno wielowątkowość, jak i usługowy charakter tych aplikacji, które z resztą powinny być w stanie wymieniać między sobą kilka podstawowych komunikatów. Koncepcja nadal się nie wyklarowała - równie dobrze może się wkrótce okazać, że ostateczne rozwiązanie przyjmie kształt farmy wielowątkowych aplikacji (usług), które będą musiały pracować w sposób skoordynowany. Zgodnie z tym, co napisane w dokumentacji - POE powinno dać sobie z tym wszystkim radę. Jakkolwiek wygoda tworzenia tego typu rozwiązań w POE mogłaby być dla dewelopera całkiem duża, o tyle nie można zapominać o wydajności końcowego produktu, który przecież zorientowany jest na masowe i logicznie skomplikowane operacje na danych. Głównym priorytetem jest więc szybkość przetwarzania. I właśnie w tym obszarze pojawia się największy problem z POE. Chodzi o to, że Perl Object Environment w obecnym kształcie nie wykorzystuje prawdziwych wątków (nie jest thread-safe, mowa oczywiście o wątkach perlowskich - interpreter threads), tylko je w swoisty sposób symuluje. Ma to swoje plusy - nie ma konieczności kopiowania do pamięci interpretera dla każdego nowego wątku, gdyż jest on współdzielony, ale... ...z drugiej strony aplikacje POE, będąc jednowątkowymi, nie są w stanie korzystać z dobrodziejstw systemów wieloprocesorowych i wielordzeniowych, co dla rozwiązania z gatunku data processing jest sporą ujmą. W moim przypadku będzie to chyba argument decydujący. Jeżeli do tworzenia aplikacji wybrany zostanie Perl jako technologia podstawowa (ze względu na natywne wsparcie dla wyrażeń regularnych), to na pewno POE jako framework nie będzie wykorzystany. POE może się jednak świetnie nadawać do innych celów, pewnie jednak się o tym nigdy nie przekonam :) Więcej informacji: http://poe.perl.org - Perl Object Environment home POE: The Perl Object Environment Whitepaper (pdf) pl.comp.lang.perl: POE (Google Groups) Deduplikacja danych: .NET vs Perl
Autor: Marcin Guzowski | Data:
16.11.2006, 22:39
| Kategorie: Świat Perla, Platforma .NET
| Komentarze (2)
| Ślad (1)
Systemy informatyczne przetwarzają coraz większe ilości danych, w naturalny sposób pojawia się więc coraz większa potrzeba ich automatycznej analizy i obróbki. Deweloperzy związani z bazami danych muszą tworzyć specyficzne, dedykowane rozwiązania, a wybór odpowiedniej technologii to praktycznie klucz do sukcesu. Chciałbym porównać dwie wybrane platformy - .NET i Perl - w hipotetycznym scenariuszu automatycznego przetwarzania danych.
Wspomniany scenariusz zakłada potrzebę wyznaczenia rekordów podobnych w bazie klientów, a dokładniej - w tabeli, która zawiera 10000 wierszy z danymi teleadresowymi (przykładowe kolumny: nazwa, miejscowość, adres, kod, nip). Dane w bazie są zwielokrotnione, tzn. kilka rekordów w rzeczywistości opisuje jednego i tego samego klienta (zapisanego oczywiście w różny sposób, np. "FIRMA HERKULES", "HERKULES S.C.", "HERKULES - SKLEP"; analogicznie z danymi adresowymi: "WIEJSKA 15", "ULICA WIEJSKA" itd.). Aby zrealizować cel, do tabeli zostanie dodana kolumna unikalnego identyfikatora, a algorytm zapełni ją odpowiednimi wartościami, przydzielając rekordom dostatecznie podobnym taki sam identyfikator. Zakładamy ponadto warunek brzegowy (minimalizacja ryzyka błędu): rekordy oznaczone jako podobne muszą posiadać identyczny NIP. Zadanie opisane wyżej to klasyczna deduplikacja danych. Od prawie 2 lat zajmuję się m.in. procesami inteligentnej analizy, przetwarzania danych i obserwuję w ostatnim czasie znaczący, dynamiczny wzrost popularności tej tematyki. Złoty wiek różnorodnych automatów właśnie się rozpoczął. Wracając do naszego scenariusza, można sobie wyobrazić co najmniej kilka koncepcji algorytmu deduplikacji, oczywiście każdy z nich ma swoje mocne i słabe strony. Skupiamy się na technologii, a nie na funkcjonalnościach - więc dodam tylko, że do oceny zgodności poszczególnych pól użyłem metody Levenshtein-Distance (google zaprasza zainteresowanych). Środowisko testowe wyglądało następująco: serwer Windows Server 2003 SE 32bit, baza danych SQL Server 2005 SP1, wszystko postawione na jednej maszynie (na której uruchamiane były również testowe implementacje). Jak widać środowisko zostało dobrane tak, żeby lekko faworyzować platformę .NET. Implementacja algorytmu w CLR (język C#) to klasyczna aplikacja obiektowa z providerem OLE DB (natywne rozwiązanie względem SQL Servera). Algorytm został również zaimplementowany w Perlu (wersja 5.8.8), dostępem do danych zajmował się moduł DBI działający na providerze ODBC. Mamy więc pojedynek technologii, za którą stoją miliardy dolarów w jej naturalnym środowisku - i - technologii open source, która dzięki wieloletniej pracy rzeszy ludzi została wysoce zoptymalizowana do przetwarzania danych, a wyrażenia regularne traktuje tak samo natywnie jak choćby instrukcję warunkową IF. Poniżej przedstawiam wyniki: (średni czas dla 3 prób) Wyraźnie zwyciężył więc Perl, który zadanie wykonał o 55% szybciej niż konkurent (jakość była jednakowa w obydwu przypadkach, zgodnie z założeniem). Nie pierwszy raz przekonałem się, że Practical Extraction and Report Language nie ma sobie równych wśród technologii do przetwarzania danych. Warto też dodać, że obydwie implementacje powstały w tak samo krótkim czasie, mimo że do stworzenia kodu w Perlu wykorzystałem zwykły edytor tekstowy, a do .NET - potężne Visual Studio 2005 z pełnym intellisense i innymi programistycznymi udogodnieniami. Perl/Tk: tips and tricks
Autor: Marcin Guzowski | Data:
30.10.2006, 22:55
| Kategorie: Świat Perla
| Komentarze (2)
| Ślady (0)
Aplikacje okienkowe napisane przy pomocy biblioteki Perl/Tk to rozwiązanie dające całkiem duże możliwości. Chciałbym pokazać kilka sztuczek, których sposób realizacji może łatwo umknąć w natłoku rozmaitej dokumentacji. Poniższe przykładowe fragmenty kodu odnoszą się do następującego skryptu szkieletowego:
#!/usr/bin/perl 1. Blokowanie zmiany rozmiaru okna Aby pozbawić naszą aplikację (lub jedno z jej okien) możliwości zmiany rozmiaru okna, musimy podpiąć do zdarzenia <Configure> tzw. callback - czyli de facto obsługę zdarzenia. W callbacku spowodujemy, że mimo działań użytkownika podejmującego próbę zmiany rozmiaru, początkowe rozmiary okna zostaną natychmiast przywrócone: $Win->bind('<Configure>' => sub { A propos, sztywne zdefiniowanie rozmiarów okna może być osiągnięte w taki sposób: $Win->minsize(qw(700 525)); gdzie 700 to oczywiście szerokość, a 525 - wysokość. 2. Obsługa zamknięcia okna Na analogicznej zasadzie jak w przykładzie powyżej możemy zablokować zamknięcie okienka przez przycisk [x] z prawego górnego rogu okna. Wymaga to użycia metody protocol: $Win->protocol('WM_DELETE_WINDOW' => sub {}); W momencie zastosowania powyższej konstrukcji aplikacja może zostać pozbawiona podstawowej funkcjonalności - czyli możliwości jej zamknięcia. Dlatego warto przekierować obsługę zdarzenia protokołu managera okien WM_DELETE_WINDOW na nie-pustą metodę, w której np. wyświetlony zostanie komunikat z odpowiednim pytaniem, nastąpią określone czynności typu zalogowanie zdarzenia zamknięcia aplikacji itd. W sytuacji wyświetlenia pytania potwierdzającego chęć zamknięcia oka (wyjścia z aplikacji), przykładowy kod wygląda następująco: sub ExitApp { 3. Skróty klawiszowe Każda porządna aplikacją powinna obsługiwać skróty klawiszowe. Perk/Tk oczywiście umożliwia wprowadzanie takiej funkcjonalności. Aby przykładowy skrót CTRL-X spowodował takie samo działania, jak wybranie przycisku [x] (zakładając zastosowanie kodu z poprzedniego punktu), wystarczy podpiąć pod określone widget event funkcję ExitApp: $Win->bind('<Control-x>' => \&ExitApp); Hash references (hash refs, hrefs)
Autor: Marcin Guzowski | Data:
10.10.2006, 20:35
| Kategorie: Świat Perla
| Komentarze (0)
| Ślady (0)
Hash referencji to najbardziej elastyczna struktura danych dostępna w Perlu. Jest to najogólniej mówiąc tablica asocjacyjna przechowująca referencje do innych zmiennych (np. następnych hashy referencji, zmiennych skalarnych, tablicowych itd.). Poniżej kilka wybranych zagadnień dla praktyków.
Hash ref deklarujemy jak zmienną skalarną: my $href; W tym momencie jest ona gotowa do użycia - nie musimy deklarować żadnego fragmentu jej struktury. Wywołanie: $href->{klucz1} = 'wartosc1'; # wartość skalarna spowoduje, że pod określonymi kluczami zostaną umieszczone odpowiednie wartości. Można także bez żadnych ograniczeń przypisać wartość/zmienną do automatycznie tworzonych hashy referencji kolejnych poziomów: $href->{klucz1_1}->{klucz2_1} = $zmienna; Zaznaczam od razu, że świadomie w przykładach nie zapisuję wartości klucza w apostrofach ('klucz' zamiast klucz). W Perlu nie ma typu danych int i string - jest typ skalarny, dlatego dopuszczalne jest zapisywanie prostych wartości klucza (jednowyrazowych) bez ciapków. Taki zapis spotykany jest często w dokumentacji, więc na pewno nie można go uznać za niepoprawny. Rzecz tylko w tym, żeby interpreter zrozumiał o co nam chodzi. Co do samego sposobu dereferencji - istnieje wiele różnych opcji zapisu odwołania do danej wartości, wszystkie poniższe są równoważne: $href->{kluczA}->{kluczB} = 'hello world'; Ze względu na czytelność kodu preferowany jest pierwszy sposób, w którym jawnie używany jest operator dereferencji (->). Możliwość tworzenia praktycznie dowolnych, zagnieżdżonych struktur to bardzo duży pozytyw, ale jednocześnie - niebezpieczeństwo zbudowania czegoś niezgodnego z intencjami. Musimy być świadomi tego, co umieszczamy jako wartość danego klucza. Przykładowo: $href->{kluczA} = ['jeden', 'dwa']; sprawi, że pod kluczem kluczA będzie znajdowała się referencja do anonimowej tablicy, a nie sama tablica. Poniższa operacja nie przyniesie więc pożądanego skutku: my @tablica = $href->{kluczA}; Prawidłowe są natomiast operacje: my @tablica = @{$href->{kluczA}}; lub bezpośrednie odwołanie do elementu tablicy z hasha: print $href->{kluczA}->[0]; Hash refs nadają się doskonale jako zmienne do przechowywania danych pobranych z BD. Wszystkie liczące się moduły dostępu do BD potrafią agregować resultsety właśnie do hashy referencji (DBI, Win32::*). Dzięki temu uzyskujemy kompleksową strukturę z bardzo szybkim skokiem do wartości - poprzez podanie określonego klucza. Pętla po elementach hasha referencji wygląda np. tak: foreach (keys %{$href}) { Dodanie jednego hash ref do drugiego osiągniemy w następujący sposób: %{$href1} = (%{$href1}, %{$href2}); Natomiast poniższa linijka kodu: print scalar(keys %{$href}); wydrukuje liczbę elementów (par klucz - wartość) hasha. Hash refs są na tyle elastyczne, że spokojnie możemy operować na ich elementach zapominając, że są one częściami większej struktury. Jesteśmy w stanie bez wysiłku przekazać referencję do samego elementu hasha: my $referencja = \$href->{klucz}->{inny_klucz}; Jak widać możliwości są praktycznie nieograniczone, taka jest z resztą specyfika samego Perla. Na koniec banalna zagadka - czym jest wartość wydrukowana na ekranie przez poniższy kod: print \$href; Odpowiedź: to referencja do zmiennej, która przechowuje referencję do hasha referencji. Brzmi skomplikowanie? Tylko pozornie.
(Strona 1 z 2, łącznie 8 wpisów)
» następna strona
|
Kalendarz
KategorieSubskrybcjaInne blogiArchiwaLipiec 2008 (0)
Czerwiec 2008 (0) Maj 2008 (0) Kwiecień 2008 (0) Marzec 2008 (0) Luty 2008 (0) Styczeń 2008 (0) Grudzień 2007 (0) Listopad 2007 (0) Październik 2007 (0) Wrzesień 2007 (0) Sierpień 2007 (0) Lipiec 2007 (0) Czerwiec 2007 (0) Maj 2007 (1) Kwiecień 2007 (1) Marzec 2007 (0) Luty 2007 (1) Styczeń 2007 (1) Grudzień 2006 (0) Listopad 2006 (1) Październik 2006 (2) Wrzesień 2006 (1) Ostatnie.... Starsze... Ostatnie wpisySecurity Update for SQL Server 7.0 - 2005
środa, lipiec 9 2008 Virtual Earth -> Geospatial Data Generator środa, lipiec 9 2008 SQL Server 2008 RTM w przyszłym tygodniu? czwartek, lipiec 3 2008 Oficjalne logo SQL Server 2008 środa, czerwiec 4 2008 SQL Server 2005 SP3 w czwartym kwartale środa, kwiecień 16 2008 V Spotkanie PLSSUG Lublin - Heroes {Community} Launch wtorek, marzec 25 2008 SQL Server 2008: fizyczny lokalizator wiersza czwartek, marzec 20 2008 Szybko, tanio, dobrze piątek, marzec 14 2008 SQL Server 2005 Service Pack 3 środa, luty 27 2008 Ciekawostki MSSQL: buffer cache z lotu ptaka sobota, luty 23 2008 SQL Server 2008 February CTP (CTP6) środa, luty 20 2008 IV Spotkanie PLSSUG Lublin poniedziałek, luty 18 2008 Ciekawostki MSSQL: Postęp niektórych operacji wtorek, luty 12 2008 Stany oczekiwań w SQL Server 2008 niedziela, luty 10 2008 WyszukajLicencja |
|||||||||||||||||||||||||||||||||||||||||||||||||
© Marcin A. Guzowski 2006-2007
http://guzowski.info

