如何利用多核提升分词速度

在进行中文分词的时候,我们如何利用多核提升分词速度呢?

计算机很早就进入多核心时代了,不充分利用多核CPU是对计算资源的一种极大的浪费。

在对一段文本进行分词的时候,word分词器的处理步骤如下:

1、把要分词的文本根据标点符号分割成句子;

2、以分割后的句子为基本单位进行分词;

3、把各个句子的分词结果按原来的句子顺序组合起来;

word分词器充分考虑到了利用多核提升分词速度这个问题,在第1步完成后,如果分割出了多个句子,那么这多个句子就可以同时(并行)进行分词,这样就能充分利用多核CPU来提升分词速度。

word分词器提出了两种解决方案,我们分别来介绍:

1、多线程

在Java中,多线程可以帮助我们充分利用CPU,我们可以根据自己的机器情况及其应用特点在配置文件word.conf中指定合适的线程池大小:

#配置分词使用的固定线程池大小,根据机器的情况设置合适的值
thread.pool.size=4

代码实现核心片段如下:

private static final ExecutorService EXECUTOR_SERVICE = Executors.newFixedThreadPool(WordConfTools.getInt("thread.pool.size", 4));
@Override
public List<Word> seg(String text) {
    List<String> sentences = Punctuation.seg(text, KEEP_PUNCTUATION);
    if(sentences.size() == 1){
        return segSentence(sentences.get(0));
    }
    //如果是多个句子,可以利用多线程提升分词速度
    List<Future<List<Word>>> futures = new ArrayList<>(sentences.size());
    for(String sentence : sentences){
        futures.add(submit(sentence));
    }
    sentences.clear();
    List<Word> result = new ArrayList<>();
    for(Future<List<Word>> future : futures){
        List<Word> words;
        try {
            words = future.get();
            if(words != null){
                result.addAll(words);
            }
        } catch (InterruptedException | ExecutionException ex) {
            LOGGER.error("获取分词结果失败", ex);
        }
    }
    futures.clear();
    return result;
}
/**
 * 将切分句子的任务提交给线程池来运行
 * @param sentence 句子
 * @return 切分结果
 */
private Future<List<Word>> submit(final String sentence){
    return EXECUTOR_SERVICE.submit(new Callable<List<Word>>(){
        @Override
        public List<Word> call() {
            return segSentence(sentence);
        }
    });
}

2、Parallel Stream

Java8 support functional-style operations on streams of elements,if we use "parallelStream()" instead of "stream()" , the serial process can automatic change to parallel process.

Java8的内置的并行处理功能,通过上面的简短的介绍我们应该有所了解,使用这种方案的好处是,随着JDK的改进,程序的性能会间接受益,而且我们的代码可以更简单,虽然我们不再能够控制并行度,比如上面我们能指定线程数,但是我们可以放心JRE会做出合理的调度与优化,而且人为指定线程数很多时候都不是最合理的。

我们可以在配置文件word.conf中指定是否启用并行分词:

#是否利用多核提升分词速度
parallel.seg=true

上面多线程的代码可以简化为:

private static final boolean PARALLEL_SEG = WordConfTools.getBoolean("parallel.seg", true);
@Override
public List<Word> seg(String text) {
    List<String> sentences = Punctuation.seg(text, KEEP_PUNCTUATION);
    if(sentences.size() == 1){
        return segSentence(sentences.get(0));
    }
    if(!PARALLEL_SEG){
        //串行顺序处理,不能利用多核优势
        return sentences.stream().flatMap(sentence->segSentence(sentence).stream()).collect(Collectors.toList());
    }
    //如果是多个句子,可以利用多核提升分词速度
    Map<Integer, String> sentenceMap = new HashMap<>();
    int len = sentences.size();
    for(int i=0; i<len; i++){
        //记住句子的先后顺序,因为后面的parallelStream方法不保证顺序
        sentenceMap.put(i, sentences.get(i));
    }
    //用数组收集句子分词结果
    List<Word>[] results = new List[sentences.size()];
    //使用Java8中内置的并行处理机制
    sentenceMap.entrySet().parallelStream().forEach(entry -> {
        int index = entry.getKey();
        String sentence = entry.getValue();
        results[index] = segSentence(sentence);
    });
    sentences.clear();
    sentences = null;
    sentenceMap.clear();
    sentenceMap = null;
    List<Word> resultList = new ArrayList<>();
    for(List<Word> result : results){
        resultList.addAll(result);
    }
    return resultList;
}

如果对更多的细节感兴趣,请点击这里查看代码的源文件

分类:word 时间:2015-05-12 人气:906
分享到:

相关文章

iOS 开发

Android 开发

Python 开发

JAVA 开发

开发语言

PHP 开发

Ruby 开发

搜索

前端开发

数据库

开发工具

开放平台

Javascript 开发

.NET 开发

云计算

服务器

Copyright (C) code.minzu.gov.cn, All Rights Reserved.

CodeMinZu 版权所有 苏ICP备163523615号

processed in 1.261 (s). 11 q(s)