Programowanie asynchroniczne - zupełnie nowa era

Programowanie asynchroniczne nie jest przyjemne. Każdy to wie. Nie dlatego że jest trudne bo można się wszystkiego nauczyć ale dlatego że kod jest nieczytelny jeżeli scenariusz wykracza poza 'Hello world'. Sam spędziłem lata pisząc rozwiązania bazowane na platformie Eclipse i moim najlepszym przyjacielem było 'asyncExec'. Jednak nawet pomimo tak przydatnych funkcji całość jest zwyczajnie nieczytelna. Pojawiło się jednak światło w tunelu - automatyczne przekształcanie kodu synchronicznego w asynchroniczny poprzez adnotacje dla kompilatora. Niestety nie jest to mechanizm dostępny w Javie ale i tak warto prezentację zobaczyć. To przyszłość każdego języka :)

Klasyczny program pisany jest imperatywnie. Komenda za komendą. Całość wywołuje się synchronicznie za pomocą jednego wątku. Jeżeli chcemy część pracy przekazać do innego wątku to musimy to jawnie napisać (stworzyć klasę anonimową np. Runnable, wywołać 'asyncExec' itp). Taki kod jednak szybko przestaje być czytelny. Trudno sobie wyobrazić czytelny kod z kilkoma zagnieżdżeniami. Nie wspominając już o obsłudze wyjątków czy wywołań zwrotnych itp. Szybko robi się z tego spagetti. Logika biznesowa w takim kodzie schodzi na plan dalszy a główne skrzypce gra tutaj aspekt techniczny kodu.

Czy to jedyna metoda? Wygląda na to że nie. Półtorej roku temu oglądałem materiały z PDC 2010 podczas których zapowiedziano iż MS pracuje nad wprowadzeniem obsługi asynchroniczności do jęzka C#. Temat wydał mi się diabelnie ciekawy ale zapomniałem o nim napisać. Wczoraj oglądając materiały z konferencji BUILD trafiłem na prezentację wersji finalnej która stała się podstawą nowego API Windows 8 (RuntimeRT).

O co chodzi? O to by programista mógł pisać zwyczajny kod wyglądający na synchroniczny ale kompilator potrafił przekształcić go w kod asynchroniczny bazowany na wywołaniach callback. Wygląda to niewiarygodnie. Można napisać metodę mającą 100 linii z czego np. 10 wywołań będzie wywołaniami asynchronicznymi. Kompilator rozbije taką metodą na serię metod zwrotnych. Nawet więcej można oznaczyć jakąś iterację że ma się wywołać równolegle a kolejna linijka kodu wykona się dopiero gdy przetworzone zostaną wszystkie elementy kolekcji. Całość sterowana dwoma prostymi słowami kluczowymi 'async' oraz 'await' umieszczanymi przy wywołaniu. To jest przyszłość jaką chciałbym kiedyś zobaczyć także w Javie.

Prezentację można zobaczyć na poniższym wideo. Poza wywołaniami asynchronicznymi architekt prezentuje jeszcze kilka innych ciekawych rozwiązań (np. pisanie programów które wywołują kompilator dodając nowe metody "w locie" które następnie ten kod wywołuje itp.). Całość jest imponująca



Mam nadzieję że Oracle znajdzie szybko porozumienie z Google i OpenJDK stanie się wspólną maszyną Javy wspieraną przez wszystkich producentów. Tak by język po kilku latach stagnacji znów rozwijał się tak szybko jak jeszcze 5 lat temu. Współpraca nad jedną wspólną maszyną wirtualną to konieczność by składnia języka dogoniła najnowsze trendy. Transformacja asynchroniczna w C# pokazuje że jeszcze sporo można zrobić na poziomie języka.

1 komentarze:

Krzysztof Kowalczyk pisze...

Pokazuje przede wszystkim 2 rzeczy, że Java strasznie zwolniła... i że języki główne coraz bardziej podchodzą do problemu od złej strony... (nie obejrzałem całego filmiku bo coś kiepsko mi działa)

W Java dodano try(resource) w C# dodano with(resource) jako elementy języka, a to powinny być standardowe funkcje biblioteczne co by było możliwe w Java gdyby np. skorzystano z domknięć BGGA. Teraz dodano async i await w C#. Fajnie, tylko znów nie ten mechanizm. Wystarczyło by pomyśleć jak dobrze wspierać metaprogramowanie, np. transformacje AST i taki mechanizm byłby dostępny w bibliotece, do napisania przez każdego. Język nie starzałby się tak drastycznie (jak Java), a dobre rozwiązania byłyby standaryzowane (tak jak JPA i Hibernate).

Rozwiązanie async w Groovy

Rozwiązanie w dobrej bibliotece do programowania współbierznego:
http://gpars.org/SNAPSHOT/guide/guide/3.%20Data%20Parallelism.html#3.5%20Composable%20Asynchronous%20Functions

Przykład z implementacja:
http://felipeg48.blogspot.com/2011/09/asynchronous-method-calls-with-groovy.html

Oba podchodzą do problemu trochę na odwrót, ale można stworzyć identyczne do C# (może byłby potrzebny lub await:, swoją drogą trochę mylące to ich nazewnictwo), w pełni statyczne rozwiązanie w Groovy++ 

Ba, można stworzyć rozwiązanie w Java! Tylko byłoby to znacznie trudniejsze, ponieważ Java nie ma żadnego standardu metaprogramowania. Mimo to project lombok funkcjonuje i na analogicznej zasadzie powinno dać się zrobić takie coś. Lombok pokazuje, że można takie rzeczy robić bez popsucia IDE.

Metaprogramowanie pozwala dorabiać dużo elementów których językowi zabrakło jak np. wsparcie dla kontraktów
https://github.com/andresteingress/gcontracts/wiki

albo porządne testy
http://code.google.com/p/spock/

To wszystko można by robić w językach statycznie typowanych, niestety puki co głównie języki dynamiczne z tego korzystają.