Generatory. Michał R. Przybyłek

Podobne dokumenty
Wątki. Definiowanie wątków jako klas potomnych Thread. Nadpisanie metody run().

Obliczenia równoległe i rozproszone w JAVIE. Michał Kozłowski 30 listopada 2003

Programowanie obiektowe

Współbieżność w środowisku Java

Java. Wykład. Dariusz Wardowski, Katedra Analizy Nieliniowej, WMiI UŁ

Kurs programowania. Wykład 1. Wojciech Macyna. 3 marca 2016

Wielowątkowość. Programowanie w środowisku rozproszonym. Wykład 1.

Język Java wątki (streszczenie)

Współbieżność i równoległość w środowiskach obiektowych. Krzysztof Banaś Obliczenia równoległe 1

Systemy Rozproszone - Ćwiczenie 4

Marcin Luckner Politechnika Warszawska Wydział Matematyki i Nauk Informacyjnych

Systemy Rozproszone - Ćwiczenie 6

Klasy abstrakcyjne i interfejsy

Java: kilka brakujących szczegółów i uniwersalna nadklasa Object

Języki i Techniki Programowania II. Wykład 7. Współbieżność 1

Dokumentacja do API Javy.

Wyjątki. Streszczenie Celem wykładu jest omówienie tematyki wyjątków w Javie. Czas wykładu 45 minut.

Kurs programowania. Wykład 8. Wojciech Macyna

Języki Programowania II Wykład 3. Java podstawy. Przypomnienie

WSPÓŁBIEŻNOŚĆ. MATERIAŁY:

Programowanie obiektowe

Dawid Gierszewski Adam Hanasko

TEMAT : KLASY DZIEDZICZENIE

Java. Programowanie Obiektowe Mateusz Cicheński

Kurs programowania. Wykład 13. Wojciech Macyna. 14 czerwiec 2017

Kurs programowania. Wykład 2. Wojciech Macyna. 17 marca 2016

Dariusz Brzeziński. Politechnika Poznańska, Instytut Informatyki

Kurs programowania. Wykład 8. Wojciech Macyna. 10 maj 2017

1. Co można powiedzieć o poniższym kodzie?

JAVA W SUPER EXPRESOWEJ PIGUŁCE

1 Wątki 1. 2 Tworzenie wątków 1. 3 Synchronizacja 3. 4 Dodatki 3. 5 Algorytmy sortowania 4

Kurs programowania. Wykład 9. Wojciech Macyna. 28 kwiecień 2016

Przetwarzanie równoległe i współbieżne

Język JAVA podstawy. Wykład 3, część 3. Jacek Rumiński. Politechnika Gdańska, Inżynieria Biomedyczna

Podstawy Programowania

Programowanie obiektowe

Java: interfejsy i klasy wewnętrzne

Interfejsy w Java. Przetwarzanie równoległe. Wątki.

Wątki (Threads) Potrzeby. Przetwarzanie równoległe i współbieŝne. Cechy programowania wątkowego. Concurrent programming is like

Programowanie obiektowe

Aplikacje Internetowe. Najprostsza aplikacja. Komponenty Javy. Podstawy języka Java

Tworzenie i wykorzystanie usług

Programowanie w języku Java - Wyjątki, obsługa wyjątków, generowanie wyjątków

Multimedia JAVA. Historia

Wątki w Javie. Piotr Tokarski

Polimorfizm. dr Jarosław Skaruz

Aplikacja wielowątkowa prosty komunikator

Model pamięci. Rafał Skinderowicz

Wywoływanie metod zdalnych

Klasy. dr Anna Łazińska, WMiI UŁ Podstawy języka Java 1 / 13

JAVA. Java jest wszechstronnym językiem programowania, zorientowanym. apletów oraz samodzielnych aplikacji.

Klasy abstrakcyjne, interfejsy i polimorfizm

Automaty do zadań specjalnych. Olga Maciaszek-Sharma, Artur Kotow Wersja 1,

public - może być używana w kodzie poza klasą, jedna klasa ModyfikatorKlasy może być kombinacją wyrażeń:

Podstawy programowania obiektowego

Programowanie obiektowe

Platformy Programistyczne Wykład z Javy dla zaawansowanych

SWING c.d. przydatne narzędzia: JFileChooser, JOptionPane. drag'n drop, menu kontekstowe.

Konstruktory. Streszczenie Celem wykładu jest zaprezentowanie konstruktorów w Javie, syntaktyki oraz zalet ich stosowania. Czas wykładu 45 minut.

Język Java wątki (streszczenie)

Podstawy współbieżności

Programowanie obiektowe

Java. język programowania obiektowego. Programowanie w językach wysokiego poziomu. mgr inż. Anna Wawszczak

Badania poziomu bezpieczeństwa portalu dostępowego do infrastruktury projektu PL-Grid

programowanie w oparciu o platformę netbeans w praktyce

Kurs programowania. Wykład 9. Wojciech Macyna

1. Co można powiedzieć o poniższym kodzie? public interface I { void m1() {}; static public void m2() {}; void abstract m3();

10. Programowanie obiektowe w PHP5

Semafor nie jest mechanizmem strukturalnym. Aplikacje pisane z użyciem semaforów są podatne na błędy. Np. brak operacji sem_post blokuje aplikację.

Języki i techniki programowania Ćwiczenia 2

Programowanie w Javie 1 Wykład i Ćwiczenia 3 Programowanie obiektowe w Javie cd. Płock, 16 października 2013 r.

Programowanie wielowątkowe. Tomasz Borzyszkowski

Dziedziczenie. Streszczenie Celem wykładu jest omówienie tematyki dziedziczenia klas. Czas wykładu 45 minut.

Programowanie współbieżne Laboratorium nr 11

Wątek - definicja. Wykorzystanie kilku rdzeni procesora jednocześnie Zrównoleglenie obliczeń Jednoczesna obsługa ekranu i procesu obliczeniowego

1 Atrybuty i metody klasowe

Programowanie współbieżne Wykład 5. Rafał Skinderowicz

Szablony funkcji i szablony klas

Remote Method Invocation 17 listopada 2010

Interfejsy. Programowanie obiektowe. Paweł Rogaliński Instytut Informatyki, Automatyki i Robotyki Politechniki Wrocławskiej

Projektowanie algorytmów rekurencyjnych

Java - tablice, konstruktory, dziedziczenie i hermetyzacja

Obiektowe programowanie rozproszone Java RMI. Krzysztof Banaś Systemy rozproszone 1

Podejście obiektowe do budowy systemów rozproszonych

Semafor nie jest mechanizmem strukturalnym. Aplikacje pisane z użyciem semaforów są podatne na błędy. Np. brak operacji sem_post blokuje aplikację.

Wywoływanie metod zdalnych

Remote Method Invocation 17 listopada Dariusz Wawrzyniak (IIPP) 1

Programowanie równoległe i rozproszone. Monitory i zmienne warunku. Krzysztof Banaś Programowanie równoległe i rozproszone 1

Wstęp do ruby dla programistów javy

Współbieżność w Javie

Operatory. Składnia. Typy proste. Znaki specjalne

Programowanie obiektowe i C++ dla matematyków

Builder (budowniczy) Cel: Przykład:

Java - wprowadzenie. Programowanie Obiektowe Mateusz Cicheński

Java niezbędnik programisty spotkanie nr 9. Java 2 Platform, Standard Edition 5.0

Enkapsulacja, dziedziczenie, polimorfizm

Autor: dr inż. Zofia Kruczkiewicz, Programowanie aplikacji internetowych 1

Technologie i usługi internetowe cz. 2

1. Co będzie wynikiem wykonania poniŝszych instrukcji? g2d.gettransform().scale(1, -1); g2d.gettransform().translate(4, -8); g2d.drawline(4, 0, 4, 4);

Wykład 12. Programowanie serwera MS SQL 2005 w C#

Transkrypt:

Generatory Michał R. Przybyłek 1 Wstęp Generator to potencjalnie nieskończony, leniwie obliczany, ciąg wartości. W zależności od tego, która ze stron decyduje o wygenerowaniu nowej wartości wyróżniamy następujące sytuacje: aktywny producent, aktywny konsument (np. Python) aktywny producent, pasywny konsument (np. Ruby) pasywny producent, aktywny konsument (np. Kogut) pasywny producent, pasywny konsument (np. serie w Common Lispie) Aktywność tutaj oznacza możliwość wygenerowania/odebrania nowej wartości w dogodnym dla siebie momencie (intuicyjnie pętla jest po stronie aktywnej), a pasywność konieczność wygenerowania/odebrania nowej wartości na żądanie (intuicyjnie pętla nie jest po naszej stronie). Generatory z aktywnym producentem zazwyczaj łatwiej się definiuje, a generatory z aktywnym konsumentem zazwyczaj wygodniej się używa. Należy jednak zwrócić uwagę, że w ogólnej sytuacji generatory z aktywnym producentem i aktywnym konsumentem wymagają od implementacji istnienia mechanizmu równoważnego jednowejściowym kontynuacjom (np. wątków). Oczywiście z punktu widzenia konsumenta tj. użytkownika generatora jest zupełnie obojętne czy strona producenta tj. implementacji generatora jest aktywna, czy pasywna. Dlatego generatory z aktywnym konsumentem będziemy po prostu nazywać aktywnymi, a generatory z pasywnym konsumentem pasywnymi. 1

2 Generatory aktywne Dla generatorów aktywnych przyjmiemy w Javie następującą abstrakcję: public interface AGenerator<T> { T value() throws StopException; AGenerator<T> next(); Metoda value() daje bieżący element generatora, bądź zgłasza wyjątek StopException (jest to ogólny wyjątek informujący o zaprzestaniu wykonywania jakiejś czynności), jeżeli na danej pozycji generator nie ma elementu (domyślnie zakładamy, że taki generator dobiegł końca). Metoda next() daje generator wskazujący na kolejną pozycję w generowanym ciągu. Przykład 2.1 (NullGenerator). Generator nie produkujący żadnych wartości: public class NullGenerator<T> implements AGenerator<T> { public NullGenerator() { public AGenerator<T> next() { return this; public T value() throws StopException { throw new StopException(); Przykład 2.2 (IntGenerator). Generator produkujący wszystkie liczby całkowite począwszy od ustalonej: public class IntGenerator implements AGenerator<Integer> { private int value; public IntGenerator(int value) { this.value = value; 2

public AGenerator<Integer> next() { return new IntGenerator(value+1); public Integer value() throws StopException { return value; Przykład 2.3 (ListGenerator). Generator produkujący po kolei wszystkie elementy danej listy: public class ListGenerator<T> implements AGenerator<T> { private T value = null; private AGenerator<T> next = null; private ListIterator<T> iter; private ListGenerator(ListIterator<T> iter) { this.iter = iter; public ListGenerator(List<T> list) { this.iter = list.listiterator(); private void force() throws StopException { if(iter!= null) { value = iter.next(); next = new ListGenerator<T>(iter); iter = null; catch(nosuchelementexception e) { throw new StopException(); public AGenerator<T> next() { 3

force(); catch(stopexception e) { return this; return next; public T value() throws StopException { force(); return value; Ćwiczenie 2.1. Mając dany następujący interfejs reprezentujący funkcje: public interface Function<S, T> { public T call(s x); zaimplementować metodę: <S, T> AGenerator<T> map(function<s, T> fun, AGenerator<S> generator) tworzącą generator wyjściowy przez sukcesywne aplikowanie funkcji fun do elementów generatora generator zaimplementować metodę: <S1, S2, T> AGenerator<T> map2(function<s1, Function<S2, T>> fun, AGenerator<S1> generator1, AGenerator<S2> generator2) tworzącą generator wyjściowy przez sukcesywne aplikowanie dwuargumentowej funkcji fun do pary elementów (korzystamy tutaj z faktu, że funkcje zwracające funkcje są esencjalnie tym samym co funkcje dwuargumentowe), gdzie pierwszy element pary brany jest z generatora generator1, a drugi z generator2; generator wyjściowy się kończy, jeżeli kończy się którykolwiek z generatorów wejściowych 4

zaimplementować metodę: <T> AGenerator<T> unfold(function<t, T> fun, T init) tworzącą generator, którego elementami są elementy ciągu: init, fun.call(init), fun.call(fun.call(init)),... 3 Generatory pasywne Dla generatorów z aktywnym producentem i pasywnym konsumentem w Javie przyjmiemy następującą abstrakcję: public interface PGenerator<T> { public void generate(code<t> code) throws StopException; gdzie interfejs Code<T> ma następującą postać: public interface Code<T> { public void execute(t x) throws StopException; Metoda generate dostaje od klienta kawałek kodu z miejscem na przekazanie wartości i wykonuje ten kod dla każdej kolejnej wygenerowanej wartości. Dla usprawnienia komunikacji pomiędzy klientem a implementacją, zezwalamy na to, aby kod klienta mógł rzucić wyjątek StopException informujący generator o zaprzestaniu generowania dalszych wartości (tak rzucony wyjątek powinien przelecieć przez samą metodę generate). Przykład 3.1 (NullGenerator). Generator nie produkujący żadnych wartości: public class NullGenerator<T> implements PGenerator<T> { public void generate(code<t> code) throws StopException { Przykład 3.2 (IntGenerator). Generator produkujący wszystkie liczby całkowite począwszy od ustalonej: 5

public class IntGenerator implements PGenerator<Integer> { private int start; public IntGenerator(int start) { this.start = start; public void generate(code<integer> code) throws StopException { for(int i = start ; true ; i++) { code.execute(i); Przykład 3.3 (ListGenerator). Generator produkujący po kolei wszystkie elementy danej listy: public class ListGenerator<T> implements PGenerator<T> { private List<T> list; public ListGenerator(List<T> list) { this.list = list; public void generate(code<t> code) throws StopException { for(t elem : list) { code.execute(elem); Ćwiczenie 3.1. Mając dany interfejs Function<S, T> jak w poprzednim ćwiczeniu zaimplementować metodę: <S, T> PGenerator<T> map(function<s, T> fun, PGenerator<S> generator) 6

tworzącą generator wyjściowy przez sukcesywne aplikowanie funkcji fun do elementów generatora generator pomyśleć dlaczego tak trudno zaimplementować jest dla pasywnych generatorów metodę (dużo ogólniejsze rozwiązanie tego problemu znajduje się w kolejnym rozdziale): <S1, S2, T> PGenerator<T> map2(function<s1, Function<S2, T>> fun, PGenerator<S1> generator1, PGenerator<S2> generator2) tworzącą generator wyjściowy przez sukcesywne aplikowanie dwuargumentowej funkcji fun do pary elementów, gdzie pierwszy element pary brany jest z generatora generator1, a drugi z generator2; generator wyjściowy się kończy jeżeli kończy się którykolwiek z generatorów wejściowych zaimplementować metodę: <T> PGenerator<T> unfold(function<t, T> fun, T init) tworzącą generator, którego elementami są elementy ciągu: init, fun.call(init), fun.call(fun.call(init)),... 4 Generatory z aktywnym producentem i aktywnym konsumentem Zamiast zaproponować nowy typ generatorów, pokażemy jak konwertować dwa opisane wyżej typy generatorów na siebie. Jak już powiedziano we wstępie, w ogólnej sytuacji możliwość tworzenia generatorów z aktywnym producentem i aktywnym konsumentem wymaga istnienia od języka silnych mechanizmów do kontroli przepływu wykonania programu, nic dziwnego zatem, że do konwersji generatorów pasywnych na aktywne będziemy musieli użyć wątków. Zacznijmy jednak od prostej sytuacji utworzenia generatora pasywnego na podstawie generatora aktywnego: 7

public class PassiveGenerator<T> implements PGenerator<T> { private AGenerator<T> generator; public PassiveGenerator(AGenerator<T> generator) { this.generator = generator; public void generate(code<t> code) { AGenerator<T> generator = this.generator; T value; while(true) { value = generator.value(); catch(stopexception e) {break; code.execute(value); generator = generator.next(); Aby skonwertować generator pasywny na aktywny postąpimy w następujący sposób: odpalimy generator pasywny w nowym wątku, a jako kod przekażemy mu synchronizowaną komórkę pamięci do takiej komórki można zapisać wartość, ale ponowna próba zapisu przed jej opróżnieniem powoduje wstrzymanie procesu; na każde żądanie obliczenia nowej wartości będziemy wyciągać wartość z komórki. Zauważmy, że przy tej definicji generator pasywny zawsze będzie produkował dwie wartości z wyprzedzeniem. Należy pamiętać przy implementacji tej konwersji o właściwym zwalnianiu nieprzydatnych już zasobów (w szczególności jeżeli nie ma już referencji do generatora aktywnego, wątek obsługujący generator pasywny powinien zostać zwolniony). public class Cell<T> { private T value; private boolean consumed; private boolean stop; public Cell() { 8

this.value = null; this.consumed = true; this.stop = false; public synchronized void put(t val) throws StopException { while(true) { if(stop == true) { throw new StopException(); if(consumed == true) { break; this.wait(); catch (InterruptedException e) { consumed = false; value = val; this.notifyall(); public synchronized T get() throws StopException { while(true) { if(consumed == false) { break; if(stop == true) { throw new StopException(); this.wait(); catch (InterruptedException e) { T val = value; value = null; consumed = true; this.notifyall(); 9

return val; public synchronized void stop() { this.stop = true; this.notifyall(); public class ActiveCode<T> implements Code<T> { private Cell<T> cell; public ActiveCode(Cell<T> cell) { super(); this.cell = cell; public void execute(t x) throws StopException { cell.put(x); public class ActiveThread<T> extends Thread { private PGenerator<T> passive; private Code<T> code; private Cell<T> cell; public ActiveThread(PGenerator<T> passive, Code<T> code, Cell<T> cell) { super(); this.passive = passive; this.code = code; this.cell = cell; public void run() { passive.generate(code); 10

catch (StopException e) { cell.stop(); public class ActiveGenerator<T> implements AGenerator<T> { private Cell<T> cell; private T value = null; private AGenerator<T> next = null; private ActiveGenerator(Cell<T> cell) { this.cell = cell; public ActiveGenerator(final PGenerator<T> passive) { this.cell = new Cell<T>(); Code<T> code = new ActiveCode<T>(cell); new ActiveThread<T>(passive, code, cell).start(); private void force() throws StopException { if(cell!= null) { value = cell.get(); next = new ActiveGenerator<T>(cell); cell = null; public AGenerator<T> next() { force(); catch(stopexception e) { return this; return next; 11

public T value() throws StopException { force(); return value; protected void finalize() { if(cell!= null) { cell.stop(); Ćwiczenie 4.1. Przekształcić tak powyższy kod, aby pasywny generator generował zawsze dokładnie tyle wartości, ile jest potrzebnych. 12