网站开发实战视频,新手学做网站 视频百度网盘,珠海市建设工程造价协会网站,网站营运这些天来#xff0c;我发布了Wordcounter #xff0c;这是一个Java库和命令行实用程序#xff0c;用于对文本文件中的单词进行计数并对单词计数进行分析#xff0c;从而大量使用了功能编程结构和并行计算方法。 这是我在“令人讨厌的快速问答”大赛第四个条目SAP #xff… 这些天来我发布了Wordcounter 这是一个Java库和命令行实用程序用于对文本文件中的单词进行计数并对单词计数进行分析从而大量使用了功能编程结构和并行计算方法。 这是我在“令人讨厌的快速问答”大赛第四个条目SAP 经过给料机 托多尔和Hanoier 。 该库使用JDK 8 lambda 以及新的JDK 7功能例如Fork / Join和NIO.2 。 它是内置的只能与支持lambda的JDK 8的早期访问版本一起使用 。 随着JDK 8中lambda及其支持功能的引入我们用Java构建软件的方式将发生变化。 如果您想了解几年后Java代码的外观可以看看Wordcounter。 与当前大多数资源不同这不是一个简单的教程而是一个实际的项目。 竞赛任务要求使用Fork / Join和lambdas实现算法该算法分析目录中的所有文件并找到文件中十个最常用的单词以及它们出现的次数。 我没有简单地坚持使用Fork / Join而是尝试找到最适合此任务的并行方法这使我选择了Producer / Consumer作为核心的单词计数逻辑。 您可以在github上探索源代码。 还有一个相当全面的自述文件它提供了更详细的文档。 最新的二进制javadoc和源代码包可在GitHub 下载部分中找到 。 如果有足够的兴趣我将在线发布Javadoc并在中央Maven存储库中提供该库。 欢迎反馈评论和贡献 总览 图书馆特色 计算字符串单个文本文件或包含文本文件的目录树中的所有单词。 分析单词计数以找到前N个最常用的单词后N个最不常用的单词或总单词数。 通过外部谓词指定字符是否为文字字符。 指定要对单词执行的可选操作例如通过外部运算符转换为小写字母。 在非并行和并行实现之间进行选择以比较其性能。 如果需要将并行度指定为与内核数不同的值。 编程要点 使用生产者/使用者来读取文件并并行计算每个文件中的单词。 实际的机制封装在通用的可重用实现中。 使用Fork / Join对字数进行分析。 这里实际的机制再次封装在通用的可重用实现中。 使用NIO.2遍历目录树和读取文件。 大量使用函数接口和lambda表达式 以便在适当的地方传递函数而不是数据。 有两个最重要的类的综合单元测试和性能测试。 像往常一样代码干净结构合理且易于阅读。 格式命名和注释是统一且一致的。 适当地使用了面向对象和功能编程技术已引起了很多关注。 命令行界面 要启动命令行程序请执行以下命令 java -jar wordcounter-1.0.4.jar options 所有选项都有合理的默认值因此都不是必需的。 对所有选项使用默认值会导致在当前目录及其子目录中找到前10个最常用的单词。 指定非默认值允许指定不同的目录分析模式单词字符单词数和并行度以及忽略大小写或使用串行而不是并行计算例如 在“单词”目录中找到最常用的10个单词-p words 在目录“ wordsx”中查找前5个最不常用的单词并将数字视为单词字符忽略大小写并进行信息记录-p wordsx -m bottom -d 1234567890 -i -n 5 -l info 有关命令行界面选项的更多信息请参见自述文件中的命令行界面 。 设计 库的设计将问题划分为通用并行处理实用程序封装用于表示原始字数和排序字数的数据结构的类最后是使用前两组功能执行计数和分析的类。 实际上所有这些类都大量使用功能接口的实例以便允许对其通用行为进行特定的自定义。 这导致代码中大量注入了lambda表达式和方法引用。 欢迎来到Java函数编程的世界 通用并行处理实用程序 ForkJoinComputer类 ForkJoinComputerT类是通用的Fork / Join计算机。 它将初始大小除以2直到达到指定的并行度或低于指定的阈值然后使用指定的ComputerT串行计算每个部分然后使用指定的MergerT将所有计算的结果MergerT 。 此处计算机和合并是定义如下的功能接口 public interface ComputerT {T compute(int lo, int hi);
}public interface MergerT {T merge(T result1, T result2);
} 可以通过简单地使用适当的lambda实例化该类然后调用其compute方法来使用此类。 new ForkJoinComputerInteger(n, 1000,(lo, hi) - { int sum 0; for (int i lo 1; i hi; i) sum i; return sum; },(a, b) - a b).compute(); ProducerConsumerExecutor类 ProducerConsumerExecutorT1, T2类是通用的Producer / Consumer执行程序。 它启动一个ProducerT1任务和多个MediatorT1, T2和ConsumerT2任务它们的数量等于指定的并行度。 生产者将T1实例放入BlockingQueueT1 。 中介者从那里获取这些实例将其转换为T2 并将其放入另一个类型为BlockingQueueT2阻塞队列中。 最后使用者从第二个阻塞队列中获取T2实例并对其进行处理。 这里 Producer, Consumer和Mediator是功能接口定义如下 public interface ProducerT {void produce(BlockT block);
}public interface ConsumerT {void consume(T t);
}public interface MediatorT1, T2 {void mediate(T1 t, BlockT2 block);
} 在上面的代码中 Block是java.util.functions定义的标准函数。 传递给Producer和Mediator方法的块将产生的数据放入相应的阻塞队列中。 与ForkJoinComputer相似可以通过在适当的lambda上实例化该类然后调用其execute方法来使用此类。 数据结构类 这些类封装了用于表示原始和已排序字数的数据结构。 WordCounts类表示映射到其使用计数的单词列表。 TopWordCounts类表示映射到具有此类计数的所有单词的单词使用情况计数的排序列表。 字数统计和分析类 WordCounter类 WordCounter类提供了一种方法用于以串行或并行方式对表示文件或目录树的Path单词进行计数。 通过使用适当的lambda实例化它然后调用其count方法可以使用它 // Count all words consisting of only alphabetic chars, ignoring case, using parallel processing
WordCounts wc new WordCounter(path, (c) - Character.isAlphabetic(c), (s) - s.toLowerCase(), true).count(); 并行实现使用ProducerConsumerExecutorPath, String 。 生产者只需遍历目录树并产生Path实例。 中介者将文件读入文本片段而使用者则对每个文本片段中的单词进行计数并将它们收集在单个WordCounts实例中。 这是通过以下代码完成的 private WordCounts countPar() {final WordCounts wc new WordCounts(parLevel);new ProducerConsumerExecutorPath, String((block) - collectPaths(block),(file, block) - readFileToBlock(file, block),(text) - wc.add(countWords(text, pred, op)), parLevel).execute();return wc;
} WordCountAnalyzer类 WordCountAnalyzer类提供了对WordCounter产生的字数进行分析的方法例如查找前N个最常用的字。 也可以通过简单地实例化它然后调用其方法之一例如findTop或total来使用它 // Find the top 10 most used words in wc
TopWordCounts twc new WordCountAnalyzer(wc, true).findTop(10, (x, y) - (y - x)); Differentnet分析类型实现内部AnalysisT接口该接口定义如下 interface AnalysisT {T compute(int lo, int hi);T merge(T r1, T r2);
} 由于以上两种方法的签名模仿了ForkJoinComputer使用的Computer和Merger功能接口因此我们可以通过以下方式对所有分析类型使用fork / join public TopWordCounts findTop(int number, ComparatorInteger comparator) {return analyse(new FindTopAnalysis(number, comparator));
}private T T analyse(AnalysisT a) {if (par) {return new ForkJoinComputerT(wc.getSize(), THRESHOLD, a::compute, a::merge, parLevel).compute();} else {return a.compute(0, wc.getSize());}
} 有关库设计的更多信息请参见自述文件中的设计。 性能 我发现并行的Producer / Consumer字数统计实现很好地适应了不同数量的内核和I / O速度。 它比串行实现要快得多。 与之不同的是当使用不切实际的大量唯一单词进行测试时并行的Fork / Join分析实现仅比串行的快并且程度适中。 由于唯一字的数量很少因此实际上比串行字慢。 下表比较了单词计数的性能并在以下条件下找到了最佳分析 CPU AMD Phenom II X4 965 3.4 GHz4核4 GB RAMWindows 7JDK 8 默认选项由字母字符组成的单词区分大小写 默认并行度等于内核数 字数统计性能 实作 档案 话 大小MB 时间毫秒 序列号 1个 10000000 〜65 2200-2400 平行 1个 10000000 〜65 500-600 序列号 100 10000000 〜65 1600-1800 平行 100 10000000 〜65 500-600 查找最佳分析性能 实作 话 最大计数 最佳 时间毫秒 序列号 2000000 10000000 10 200-250 平行 2000000 10000000 10 200-250 玩代码 如果您想使用这些代码我建议您使用最新的NetBeans 7.3 beta在撰写本文时为NetBeans IDE 7.3 Beta 2 。 请注意即使在此版本中也无法在IDE中编译lambda因此周围到处都有红色标记。 但是从IDE启动Maven构建并运行测试仍然可以正常工作。 根据此博客文章 应该可以对lambda使用IntelliJ IDEA 12 EAP内部版本122.202或更高版本但是我没有亲自尝试过。 我确实尝试了Eclipse但由于Eclipse使用了自己的对lambda不了解的JDT编译器因此发现它是一场失败的比赛。 结论 这是我第一次接触Java函数编程。 尽管Java仍然不是Scala但是与我以前的Java代码相比新的函数式编程结构大大改变了我设计和实现Wordcounter的方式。 我发现这种新的编程风格是强大而富有表现力的并且我相信随着Java 8的发布它将很快成为主流。 对我来说这也是最后的“怪异敏捷”任务。 评审团慷慨地授予了我的意见书甚至在比赛结束之前我就找到了自己的优胜者。 如果这篇文章引起了您的兴趣请随时下载并浏览Wordcounter用它来学习新的Java函数编程构造并让我知道我是否可以在此过程中为您提供帮助。 参考 Wordcounter来自JCG合作伙伴 Stoyan Rachev的Lambdas和Fork / Join在Java中计算单词数网址 为Stoyan Rachev博客。 翻译自: https://www.javacodegeeks.com/2012/12/wordcounter-counting-words-in-java-with-lambdas-and-forkjoin.html