2010-04-28 1 views
4

Передача сообщений с участием актеров великолепна. Но я хотел бы иметь еще более простой код.Есть ли реализация быстрого параллельного синтаксического сахара в scala? например. map-reduce

Примеры (Псевдо-код)

val splicedList:List[List[Int]]=biglist.partition(100) 
val sum:Int=ActorPool.numberOfActors(5).getAllResults(splicedList,foldLeft(_+_)) 

где spliceIntoParts получается один большой список в 100 небольших списки numberofactors части, создает пул, который использует 5 актеров и получает новые рабочие места после того, как работа закончена и getallresults использует метод в списке. все это делается с передачей сообщений в фоновом режиме. где возможно getFirstResult, вычисляет первый результат и останавливает все остальные потоки (например, взламывает пароль)

ответ

2

Вы можете сделать это с меньшими затратами, чем создание актеров с помощью фьючерсов:

import scala.actors.Futures._ 
val nums = (1 to 1000).grouped(100).toList 
val parts = nums.map(n => future { n.reduceLeft(_ + _) }) 
val whole = (0 /: parts)(_ + _()) 

Вы должны обрабатывать разлагать проблему и писать «будущее» блок и перекомпоновкой его к окончательному ответу, но делает выполнение параллельной работы небольших блоков кода параллельно.

(Обратите внимание, что _() в складке слева функция применяется в будущем, а это значит, «Дай мне ответ вы вычислительные параллельно!», И он блокирует, пока ответ не доступен.)

Параллельная библиотека коллекций автоматически разложит проблему и перестроит ответ для вас (как с pmap в Clojure); это еще не часть основного API.

+0

Да, я вижу 'getAllResults', но как насчет' getFirstResultandThrowAwayEverythingElseFunction'? Вместо использования 'all' нам понадобится' any' – TiansHUo

+0

Это больше работает прямо сейчас - и не очень эффективно на любом языке, заметьте - и будет включать замену 'future' на' actor {loop {react {/ * код корпуса * /}}}! сообщение ", а затем получение первого ответа и игнорирование остальных. Во всяком случае, дело в том, что вы можете, конечно, создать его из актеров (даже с автоматическим выводом, если вы используете ссылку), но он не существует из коробки. Улучшенный параллелизм является одним из основных фокусов 2.9. –

+0

2.9? И когда это? Или я должен спросить, когда Scala готова для основного производства? (Да, есть твиттер, но есть только твиттер) – TiansHUo

3

Вы можете использовать функции параллелизма Scalaz, чтобы достичь того, чего хотите.

import scalaz._ 
import Scalaz._ 
import concurrent.strategy.Executor 
import java.util.concurrent.Executors 

implicit val s = Executor.strategy[Unit](Executors.newFixedThreadPool(5)) 

val splicedList = biglist.grouped(100).toList 
val sum = splicedList.parMap(_.sum).map(_.sum).get 

Было бы довольно легко сделать это похорошела (то есть написать функцию MapReduce, что делает расщепление и складывая все в одном). Кроме того, parMap над списком излишне строгий. Вы захотите начать складывать до того, как весь список будет готов. Больше как:

val splicedList = biglist.grouped(100).toList 
val sum = splicedList.map(promise(_.sum)).toStream.traverse(_.sum).get 
+0

Я считаю, что скалаз слишком плохо документирован для использования в производстве, надеюсь, что он улучшится через несколько месяцев. – TiansHUo

+0

Мы работаем над документацией. Код действительно прост, поэтому, grokking источник является следующей лучшей вещью для вашего собственного. – Apocalisp

1

В Scala Days 2010, там была очень интересная беседа Александра Prokopec (который работает на Scala в EPFL) о Parallel Collections. Это, вероятно, будет в 2.8.1, но вам, возможно, придется подождать немного дольше. Я посмотрю, смогу ли я сам получить презентацию. для связи здесь.

Идея состоит в том, чтобы иметь структуру коллекций, которая распараллеливает обработку коллекций, делая то, что вы предлагаете, но прозрачно для пользователя. Все, что вам теоретически нужно сделать, это изменить импорт из scala.collections в scala.parallel.collections. Вы, очевидно, все еще должны выполнить работу, чтобы увидеть, действительно ли то, что вы делаете, может быть распараллелировано.

+0

Чтобы превратить любую коллекцию в параллельную версию, вам нужен только «монадный трансформатор» PromiseT [M] ', который изоморфен M [Promise [A]]. Неявное преобразование из PromiseT [M] #Apply [A] в M [A] сделает трансформатор полностью прозрачным. – Apocalisp

+0

2,8,1? и когда это будет выпущено? – TiansHUo

2

Я не жду Scala 2.8.1 или 2.9, он предпочел бы быть лучше, чтобы написать свою собственную библиотеку или использовать другой, так что я сделал больше, и прибегая к помощи нашел это: Akka http://doc.akkasource.org/actors

, который имеет объектные фьючерсы с методами

awaitAll(futures: List[Future]): Unit 
awaitOne(futures: List[Future]): Future 

но http://scalablesolutions.se/akka/api/akka-core-0.8.1/ не имеет никаких документов вообще. Плохо.

Но хорошая часть в том, что актеры AKKA являются компактнее, чем родные SCALA в
С учетом всех этих библиотек (в том числе scalaz) вокруг, было бы очень здорово, если бы сама Скала может в конечном итоге объединить их официально

4

С Scala Параллельные коллекции, которые будут включены в 2.8.1, вы будете в состоянии сделать что-то вроде этого:

val spliced = myList.par // obtain a parallel version of your collection (all operations are parallel) 
spliced.map(process _) // maps each entry into a corresponding entry using `process` 
spliced.find(check _) // searches the collection until it finds an element for which 
         // `check` returns true, at which point the search stops, and the element is returned 

и код будет автоматически выполняться параллельно. Другие методы, найденные в обычной библиотеке коллекций, также распараллеливаются.

В настоящее время 2.8.RC2 очень близко (на этой или следующей неделе), и 2.8 финала придет через несколько недель после, я думаю. Вы сможете попробовать параллельные коллекции, если используете ночные часы 2.8.1.

+0

2.8.1 так скоро! Ницца! –

+0

Ничего себе, это выглядит действительно здорово. Думаю, foldLeft тоже может работать здесь – TiansHUo