동시 프로그래밍의 호출 가능 / 미래 인터페이스 (예 : 단어 베스트 매칭 알고리즘 사용)

목차

하나, Callable 인터페이스 인식

둘째, 미래 인터페이스 인식

3. 예 : 최고의 단어 일치

1. 최단 편집 거리 알고리즘 구현

2. 가장 일치하는 결과 저장

3. 사전로드

넷째, 직렬 버전

다섯, 동시 버전

1. BestMatchingBasicTask 클래스

2. BestMatchingBasicConcurrentCalculation 클래스

3. BestMatchingConcurrentMain 클래스

여섯, 검증 결과

1. 시리얼 버전 결과

2. 동시 버전 결과


하나, Callable 인터페이스 인식

Java 멀티 스레딩에 대한 지식은 매우 풍부합니다. 그 전에는 Runnable 인터페이스의 실행 작업 만 이해했습니다. 추가 연구를 통해 Java에 유사한 기능을 가진 또 다른 멀티 스레드 작업 인터페이스 인 Callable 인터페이스 가 실제로 있음을 발견 했습니다 ..

Runnable과 Callable 인터페이스의 차이점은 후자는 인터페이스의 call 메서드를 구현 한 후 반환 값을 제공한다는 점입니다. 인터페이스 메서드의 차이점은 다음과 같습니다.

실행 가능한 인터페이스

public class A implements Runnable{
    /**
     * @param 
     * @return void
     * @author Charzous
     * @date 2021/1/28 14:59
     *
     */
    @Override
    public void run() {

    }
}

호출 가능한 인터페이스 

public class A implements Callable {
    /**
     * @param 
     * @return java.lang.Object
     * @author Charzous
     * @date 2021/1/28 15:00
     *
     */
    @Override
    public Object call() throws Exception {
        return null;
    }
}

이 학습 기록은 Callable 인터페이스의 세부 사항과 응용 프로그램을 소개합니다.

Callable 인터페이스의 주요 기능 :

  1.  일반 인터페이스이며 호출 메소드의 리턴 유형은 유형 매개 변수와 동일합니다.
  2. 실행자가 작업을 실행할 때 실행되는 call 메서드가 선언됩니다.
  3. 모든 종류의 확인 예외가 발생할 수 있으며 상위 수준 응용 프로그램으로 간주되어야합니다.

둘째, 미래 인터페이스 인식

Future 인터페이스와 Callable 인터페이스는 동시에 실행 태스크에 나타나며 Callable 인터페이스의 처리 결과는 Future 인터페이스와 함께 패키징되어야합니다. Future 인터페이스는 비동기 계산 결과를 설명합니다.

Callable 작업을 실행자에게 보내면 작업의 실행 및 작업 상태를 제어하고 결과를 얻는 데 사용할 수있는 Future 인터페이스의 구현을 반환합니다.

미래 인터페이스의 주요 기능 :

  1. cancel 메소드를 사용하여 작업 실행을 취소 할 수 있습니다.
  2. 작업 상태를 확인합니다. isCancelled 메서드가 취소되었는지 여부 및 isDone () 메서드가 종료되는지 여부.
  3. get () 메서드를 사용하여 작업 반환 값을 가져옵니다.

3. 예 : 최고의 단어 일치

여기서는 간단한 사례에서 시작하여 실제 애플리케이션에서 Callable 인터페이스 및 Future 인터페이스의 구현 프로세스를 학습합니다.

최상의 단어 매칭 알고리즘최단 편집 거리 문제 의 특정 응용 이라고도 할 수 있습니다 . 목표는 두 문자열 사이의 최소 거리를 계산하는 것입니다. 요컨대 첫 번째 문자열이 두 번째 문자가됩니다. 수정 된 문자의 최소 수 문자열의.

단어 매칭 작업에서는 주어진 문자열 단어에 대해 사전에서 가장 유사한 단어를 찾는 것입니다.

준비 사항은 다음과 같습니다.

  1. 영어 사전 : UKACD , 영국 고급 난이도 사전 , 250,000 개 이상의 단어와 관용구가 포함되어 있으며 특히 십자말 풀이에 사용됩니다.
  2. 단어 간의 유사성 측정 : Lenvenshtein 거리는 첫 번째 문자열을 두 번째 문자열로 변환하는 데 필요한 삽입, 삭제 또는 대체 작업의 최소 수를 나타냅니다. 즉, 위에서 언급 한 최단 편집 거리, 알고리즘은 동적 프로그래밍을 사용하여 구현됩니다 .

다음은 최상의 단어 매칭 사례를 구현하기위한 알고리즘으로 알고리즘의 효율성을 비교하기위한 직렬 버전과 동시 버전이 있습니다. 두 알고리즘의 공통 클래스에는 최단 편집 거리 알고리즘의 실현, 최적 일치 알고리즘의 결과 저장 및 사전로드가 포함됩니다.

1. 최단 편집 거리 알고리즘 구현

이 알고리즘은 동적 프로그래밍을 사용하여 m * n 2 차원 배열 채우기를 완료하고 마지막으로 a [m] [n]에 저장된 최단 거리에 해당하는 값을 얻습니다.

public class LevenshteinDistance {
    /**
     * @param string1
     * @param string2
     * @return int
     * @author Charzous
     * @date 2021/1/28 11:10
     */
    public static int calculate(String string1, String string2) {
        int[][] distances = new int[string1.length() + 1][string2.length() + 1];
        for (int i = 1; i <= string1.length(); i++)
            distances[i][0] = i;

        for (int j = 1; j <= string2.length(); j++)
            distances[0][j] = j;
        //动态规划填表
        for (int i = 1; i <= string1.length(); i++) {
            for (int j = 1; j <= string2.length(); j++) {
                if (string1.charAt(i - 1) == string2.charAt(j - 1))
                    distances[i][j] = distances[i - 1][j - 1];
                else
                    distances[i][j] = minimum(distances[i - 1][j], distances[i][j - 1], distances[i - 1][j - 1]) + 1;
            }
        }
//测试
//        for (int i=0;i<=string1.length();i++){
//            for (int j=0;j<=string2.length();j++)
//                System.out.print(distances[i][j]+" ");
//            System.out.println();
//        }
        return distances[string1.length()][string2.length()];
    }

    private static int minimum(int i, int j, int k) {
        return Math.min(i, Math.min(j, k));
    }
/**类内测试
public static void main(String[] args) {
String s1="lonx";
String s2="long";
int d=LevenshteinDistance.calculate(s1,s2);
System.out.println(d);
}
 */
}

2. 가장 일치하는 결과 저장

 

import java.util.List;

public class BestMatchingData {
    private int distance;
    private List<String> words;

    public int getDistance() {
        return distance;
    }

    public List<String> getWords() {
        return words;
    }

    public void setDistance(int distance) {
        this.distance = distance;
    }

    public void setWords(List<String> words) {
        this.words = words;
    }
}

 

3. 사전로드

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;

public class WordsLoader {
    /**
     * @param path
     * @return java.util.List<java.lang.String>
     * @author Charzous
     * @date 2021/1/28 11:10
     */
    public static List<String> load(String path) {
        Path file = Paths.get(path);
        List<String> data = new ArrayList<String>();
        try (
                InputStream in = Files.newInputStream(file);
                BufferedReader reader = new BufferedReader(new InputStreamReader(in))) {
            String line = null;
            while ((line = reader.readLine()) != null)
                data.add(line);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return data;
    }
}

넷째, 직렬 버전

먼저 동시 처리 성능을 확인하는 데 사용할 간단한 직렬 버전을 구현합니다. 구현 아이디어는 비교적 간단하며 주어진 문자열과 사전의 각 단어 사이의 거리를 계산 한 다음 목록에 최상의 결과를 저장합니다.

import java.util.ArrayList;
import java.util.List;

public class BestMatchingSerialCalculation {
    /**
     * @param word
     * @param dictionary
     * @author Charzous
     * @date 2021/1/28 11:19
     */
    public static BestMatchingData getBestMatchingWords(String word, List<String> dictionary) {
        List<String> results = new ArrayList<String>();
        int minDistance = Integer.MAX_VALUE;
        int distance;
        for (String str : dictionary) {
            distance = LevenshteinDistance.calculate(word, str);
            if (distance < minDistance) {
                results.clear();
                minDistance = distance;
                results.add(str);
            } else if (distance == minDistance) {
                results.add(str);
            }

        }
        BestMatchingData result = new BestMatchingData();
        result.setWords(results);
        result.setDistance(minDistance);

        return result;
    }

}

다음은 실행 가능한 메인 클래스 main을 구현하고, 사전 파일을로드하고, 가장 일치하는 결과 및 관련 정보를 인쇄합니다.

import java.util.Date;
import java.util.List;

public class BestMatchingSerialMain {
    public static void main(String[] args) {
        Date startTime,endTime;
        List<String> dictionary= WordsLoader.load("data/UK Advanced Cryptics Dictionary.txt");
        System.out.println("Dictionary Size:"+dictionary.size());

        String word="stitter";//待匹配单词
        if (args.length==1)
            word=args[0];

        startTime=new Date();
        BestMatchingData result=BestMatchingSerialCalculation.getBestMatchingWords(word,dictionary);
        endTime=new Date();
        List<String> results=result.getWords();
        System.out.println("Word: "+word);
        System.out.println("Minimum distance: "+result.getDistance());
        System.out.println("耗时:"+(endTime.getTime()-startTime.getTime())+" ms");
        System.out.println("List of best matching words: "+results.size());
        results.forEach(System.out::println);
    }
}

 결과는 나중에 비교됩니다.

다섯, 동시 버전

이 시점까지 실행자 작업은 Callable 인터페이스를 기반으로 구현되며 다음과 같이 도입 된 3 개의 구현 클래스를 포함하여 가장 일치하는 단어 결과를 얻기 위해 call 메서드의 반환 값을 사용합니다.

1. BestMatchingBasicTask 클래스

여기에서는 실행기에서 Callable 인터페이스를 구현하는 작업을 실행합니다.

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;

public class BestMatchingBasicTask implements Callable<BestMatchingData> {
    private int startIdx;
    private int endIdx;
    private List<String> dictionary;
    private String word;
    /**
     * @param startIdx
     * @param endIdx
     * @param dictionary
     * @param word
     * @return 
     * @author Charzous
     * @date 2021/1/28 16:24
     *
     */
    public BestMatchingBasicTask(int startIdx, int endIdx, List<String> dictionary, String word) {
        this.startIdx = startIdx;
        this.endIdx = endIdx;
        this.dictionary = dictionary;
        this.word = word;
    }

    @Override
    public BestMatchingData call() throws Exception {
        List<String> results = new ArrayList<String>();
        int minDistance = Integer.MAX_VALUE;
        int distance;
        for (int i = startIdx; i < endIdx; i++) {
            distance = LevenshteinDistance.calculate(word, dictionary.get(i));//计算给出单词与词典中单词的距离
            //保存最佳匹配结果的单词
            if (distance < minDistance) {
                results.clear();
                minDistance = distance;
                results.add(dictionary.get(i));
            } else if (distance == minDistance)
                results.add(dictionary.get(i));
        }
        //将结果保存并返回
        BestMatchingData result = new BestMatchingData();
        result.setWords(results);
        result.setDistance(minDistance);
        return result;
    }
}

2. BestMatchingBasicConcurrentCalculation 클래스

이 클래스는 실행기와 필요한 작업을 만들고 실행자에게 작업을 보냅니다.

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadPoolExecutor;

public class BestMatchingBasicConcurrentCalculation {
    /**
     * @param word
     * @param dictionary
     * @author Charzous
     * @date 2021/1/28 16:27
     *
     */
    public static BestMatchingData getBestMatchingWords(String word, List<String> dictionary) throws ExecutionException, InterruptedException {

        int numCores = Runtime.getRuntime().availableProcessors();
        ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(numCores);
        int size = dictionary.size();
        int step = size / numCores;
        int startIdx, endIdx;
        List<Future<BestMatchingData>> results = new ArrayList<>();

        for (int i = 0; i < numCores; i++) {
            startIdx = i * step;
            if (i == numCores - 1)
                endIdx = dictionary.size();
            else
                endIdx = (i + 1) * step;
            //创建任务
            BestMatchingBasicTask task = new BestMatchingBasicTask(startIdx, endIdx, dictionary, word);
            Future<BestMatchingData> future = executor.submit(task);//执行器提交任务并获取Future接口返回结果
            results.add(future);
        }
        executor.shutdown();

        List<String> words = new ArrayList<String>();
        int minDistance = Integer.MAX_VALUE;
        for (Future<BestMatchingData> future : results) {
            BestMatchingData data = future.get();
            if (data.getDistance() < minDistance) {
                words.clear();
                minDistance = data.getDistance();
                words.addAll(data.getWords());
            } else if (data.getDistance() == minDistance)
                words.addAll(data.getWords());
        }
        BestMatchingData result = new BestMatchingData();
        result.setDistance(minDistance);
        result.setWords(words);
        return result;
    }
}

3. BestMatchingConcurrentMain 클래스

실행 가능한 메인 클래스 main을 구현하고 결과를 인쇄합니다.

import java.util.Date;
import java.util.List;
import java.util.concurrent.ExecutionException;

public class BestMatchingConcurrentMain {
    public static void main(String[] args) {
        try {
            Date startTime,endTime;
            List<String> dictionary= WordsLoader.load("data/UK Advanced Cryptics Dictionary.txt");
            System.out.println("Dictionary Size:"+dictionary.size());

            String word="stitter";//待匹配单词
            if (args.length==1)
                word=args[0];

            startTime=new Date();
            BestMatchingData result=BestMatchingBasicConcurrentCalculation.getBestMatchingWords(word,dictionary);
            endTime=new Date();
            List<String> results=result.getWords();
            System.out.println("Word: "+word);
            System.out.println("Minimum distance: "+result.getDistance());
            System.out.println("耗时:"+(endTime.getTime()-startTime.getTime())+" ms");
            System.out.println("List of best matching words: "+results.size());
            results.forEach(System.out::println);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}

여섯, 검증 결과

1. 시리얼 버전 결과

문자열 stitter를 테스트하고 사전을 검색하여 9 개의 단어와 가장 일치하는 단어를 찾으십시오.

우발 상황을 피하기 위해 여러 번의 테스트 실행이 수행되었으며 직렬 방법은 약 240ms 가 소요되었습니다 .

앉아있는
skitter
slitter
spitter
Asked
stint

stutter
titter를 지원합니다.

2. 동시 버전 결과

동시 버전은 결과를 여러 번 테스트하고 실행했으며 , 직렬 시간의 절반에 해당하는 120ms 가량 걸리며 성능이 향상됩니다.

최고의 단어 매칭 알고리즘을 예로 들어, Callable 인터페이스와 Java 동시 프로그래밍의 Future 인터페이스를 배우고, 내부 운영 메커니즘을보다 깊고 구체적으로 이해하고 동시에이 실용적인 응용 프로그램, 동적 프로그래밍 및 최단 편집 거리 알고리즘.

좋아요, 북마크, 팔로우, 질문이 있으면 직접 댓글 달기, 교환하고 배우는 등 "원 클릭, 3 링크"에 오신 것을 환영합니다!


내 CSDN 블로그 : https://blog.csdn.net/Charzous/article/details/113338669

추천

출처blog.csdn.net/Charzous/article/details/113338669