package fj.demo.concurrent; import fj.*; import fj.control.parallel.ParModule; import static fj.control.parallel.ParModule.parModule; import fj.control.parallel.Promise; import fj.control.parallel.Strategy; import static fj.data.LazyString.fromStream; import fj.data.List; import static fj.data.List.list; import fj.data.Option; import static fj.data.Option.fromNull; import fj.data.Stream; import static fj.data.Stream.fromString; import static fj.Monoid.longAdditionMonoid; import java.io.BufferedReader; import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.util.concurrent.ExecutorService; import static java.util.concurrent.Executors.newFixedThreadPool; /* Performs a parallel word count over files given as program arguments. */ public class MapReduce { // Count words of documents in parallel public static Promise<Long> countWords(final List<Stream<Character>> documents, final ParModule m) { return m.parFoldMap(documents, document -> (long) fromStream(document).words().length(), longAdditionMonoid ); } // Main program does the requisite IO gymnastics public static void main(final String[] args) { final List<Stream<Character>> documents = list(args).map( F1Functions.andThen(fileName -> { try { return new BufferedReader(new FileReader(new File(fileName))); } catch (FileNotFoundException e) { throw new Error(e); } }, new F<BufferedReader, Stream<Character>>() { public Stream<Character> f(final BufferedReader reader) { final Option<String> s; try { s = fromNull(reader.readLine()); } catch (IOException e) { throw new Error(e); } if (s.isSome()) return fromString(s.some()).append(() -> f(reader)); else { try { reader.close(); } catch (IOException e) { throw new Error(e); } return Stream.nil(); } } })); final ExecutorService pool = newFixedThreadPool(16); final ParModule m = parModule(Strategy.executorStrategy(pool)); System.out.println("Word Count: " + countWords(documents, m).claim()); pool.shutdown(); } }