2012-10-12 19 views
5

The easiest way to convert a Java Collection to a Scala equivalent is using JavaConversions, since Scala 2.8.. Te niejawne defs zwracają opakowania dla zawartej kolekcji Java.Tworzenie równoległej kolekcji Scala z kolekcji Java

Scala 2.9 wprowadziła kolekcje równoległe, w których operacje na kolekcji mogą być wykonywane równolegle, a wynik zbierany później. Można to łatwo wdrożony, przekształcając istniejącą kolekcję do równoległego jeden jest tak proste, jak:

myCollection.par 

Ale jest problem z użyciem „par” na zbiorach konwertowane z kolekcji Java z wykorzystaniem JavaConversions. Jak opisano w Parallel Collection Conversions nieodłącznie zbiory sekwencyjne są „wymuszone” do nowego zbioru równoległym oceny wszystkich wartości, dodając je do nowego zbioru równolegle:

innych kolekcji, takich jak listy, kolejki lub strumieni są z natury sekwencyjny w tym sensie, że elementy muszą być dostępne po drugim po . Kolekcje te są konwertowane na ich równoległe warianty przez skopiowanie elementów do podobnej kolekcji równoległej. Dla przykładu lista funkcjonalna jest konwertowana na standardową niezmienną równoległą sekwencję, która jest równoległym wektorem.

Powoduje to problemy, gdy oryginalna kolekcja Java ma być leniwie oceniana. Na przykład, jeśli tylko Iterowalna Java jest zwracana, później przekształcona w Scala Iterable, nie ma gwarancji, że zawartość Iterable ma być dostępna z zapałem lub nie. Jak zatem utworzyć kolekcję równoległą z kolekcji Java bez konieczności ponoszenia kosztów związanych z oceną każdego elementu? To jest ten koszt, którego próbuję uniknąć, używając kolekcji równoległej, aby wykonać je równolegle i mam nadzieję, że "wezmę" pierwsze n wyników, które są oferowane.

Zgodnie z istnieje szereg typów kolekcji, które kosztują stały czas, ale nie wydaje się, aby można było uzyskać gwarancję, że typy te można utworzyć za pomocą JavaConversions (np. Można utworzyć zestaw "Set", ale czy jest to "HashSet"?).

+1

Należy zauważyć, że lepszym pomysłem byłoby użycie JavaConverters zamiast JavaConversions jako tych ostatnich, ponieważ tam można byłoby zrobić coś takiego jak .asScala.toList.par. –

Odpowiedz

4

Po pierwsze, każda kolekcja uzyskana za pośrednictwem kolekcji Java nie jest domyślną, zrównolegloną kolekcją Scala - oznacza to, że zawsze będzie podlegać ponownej ocenie w odpowiadającej jej implementacji kolekcji równoległej. Powodem tego jest to, że wykonanie równoległe opiera się przynajmniej na pojęciach z Splitters - musi być rozdzielany na mniejsze podzbiory, na których mogą następnie pracować różne procesory.

Nie wiem, jak wygląda kolekcja Java w sensie struktury danych, ale jeśli jest to obiekt podobny do drzewa lub tablica, której elementy są leniwie oceniane, istnieje duże prawdopodobieństwo, że można łatwo zaimplementować Splitter.

Jeśli nie chcesz się ochoczo force leniwej kolekcji, która implementuje interfejs API kolekcji Java, wówczas jedyną opcją jest implement a new type of a parallel collection dla tej konkretnej leniwej kolekcji Java. W tej nowej implementacji musisz podać sposób dzielenia iteratora (czyli Splitter).

Po zaimplementowaniu tej nowej kolekcji równoległej, która wie, jak podzielić strukturę danych, należy utworzyć niestandardowe opakowanie Scala dla konkretnej kolekcji Java (w tym momencie jest to tylko trochę dodatkowych elementów, zobacz, jak to się robi w JavaConversions) i zastąp jego par, aby zwrócić swoją określoną kolekcję równoległą.

Możesz nawet zrobić to ogólnie dla indeksowanych sekwencji. Biorąc pod uwagę, że kolekcja Java jest sekwencją (w Javie, List) ze szczególnie wydajną metodą get, można wdrożyć Splitter jako iterator, który wywołuje get w zakresie początkowym od 0 do size - 1 i jest dzielony przez podzielenie tego zakresu.

Jeśli to zrobisz, poprawki do biblioteki Standard będą zawsze mile widziane.

1

Równoległa wymaga dostępu losowego i java.lang.Iterable nie zapewnia tego. Jest to podstawowa niedopasowanie, którego żadna liczba konwersji nie ułatwi ci przejścia.

Aby użyć analogii nieprogramowej, nie można dostać osoby z Australii do Anglii, wysyłając jedną osobę z Singapuru do Anglii, a drugą z Australii do Singapuru w tym samym czasie.

Lub w programowaniu, jeśli przetwarzasz transmisję danych na żywo, nie można dokonać paralelizacji, przetwarzając dane od teraz w tym samym czasie, co dane sprzed pięciu minut bez dodawania opóźnień.

Potrzebowałbyś czegoś, co zapewnia przynajmniej jakiś losowy dostęp, jak java.util.List.listIterator (Int) zamiast Iterable.

+0

Chyba założyłem, że każde wywołanie do pobrania następnego elementu (tj. Iterable.iterator(). Next()) zostało uruchomione wewnątrz wątku. –