Как сделать этот фрагмент кода безопасным? - PullRequest
0 голосов
/ 05 октября 2018

Этот код является частью метода.Код проходит через два списка, используя два цикла for.Я хочу посмотреть, есть ли возможность использования многопоточности для ускорения этого процесса для двух циклов.Меня беспокоит то, как сделать его безопасным.

РЕДАКТИРОВАТЬ: более полный код

static class Similarity {
        double similarity;
        String seedWord;
        String candidateWord;

        public Similarity(double similarity, String seedWord, String candidateWord) {
            this.similarity = similarity;
            this.seedWord = seedWord;
            this.candidateWord = candidateWord;
        }

        public double getSimilarity() {
            return similarity;
        }

        public String getSeedWord() {
            return seedWord;
        }

        public String getCandidateWord() {
            return candidateWord;
        }
    }

    static class SimilarityTask implements Callable<Similarity> {
        Word2Vec vectors;
        String seedWord;
        String candidateWord;
        Collection<String> label1;
        Collection<String> label2;

        public SimilarityTask(Word2Vec vectors, String seedWord, String candidateWord, Collection<String> label1, Collection<String> label2) {
            this.vectors = vectors;
            this.seedWord = seedWord;
            this.candidateWord = candidateWord;
            this.label1 = label1;
            this.label2 = label2;
        }

        @Override
        public Similarity call() {
            double similarity = cosineSimForSentence(vectors, label1, label2);
            return new Similarity(similarity, seedWord, candidateWord);
        }
    }

Теперь, этот поток вычислений безопасен?Здесь задействованы 3 переменные:

1) vectors;
  2) toeknizerFactory;
  3) similarities;

public static void compute() throws Exception {

        File modelFile = new File("sim.bin");
        Word2Vec vectors = WordVectorSerializer.readWord2VecModel(modelFile);

        TokenizerFactory tokenizerFactory = new TokenizerFactory()

        List<String> seedList = loadSeeds();
        List<String> candidateList = loadCandidates();

        log.info("Computing similarity: ");

        ExecutorService POOL = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
        List<Future<Similarity>> tasks = new ArrayList<>();
        int totalCount=0;
        for (String seed : seedList) {
            Collection<String> label1 = getTokens(seed.trim(), tokenizerFactory);
            if (label1.isEmpty()) {
                continue;
            }
            for (String candidate : candidateList) {
                Collection<String> label2 = getTokens(candidate.trim(), tokenizerFactory);
                if (label2.isEmpty()) {
                    continue;
                }
                Callable<Similarity> callable = new SimilarityTask(vectors, seed, candidate, label1, label2);
                tasks.add(POOL.submit(callable));
                log.info("TotalCount:" + (++totalCount));
            }
        }

        Map<String, Set<String>> similarities = new HashMap<>();
        int validCount = 0;
        for (Future<Similarity> task : tasks) {
            Similarity simi = task.get();
            Double similarity = simi.getSimilarity();
            String seedWord = simi.getSeedWord();
            String candidateWord = simi.getCandidateWord();

            Set<String> similarityWords = similarities.get(seedWord);
            if (similarity >= 0.85) {
                if (similarityWords == null) {
                    similarityWords = new HashSet<>();
                }
                similarityWords.add(candidateWord);
                log.info(seedWord + " " + similarity + " " + candidateWord);
                log.info("ValidCount: "  + (++validCount));
            }

            if (similarityWords != null) {
                similarities.put(seedWord, similarityWords);
            }
        }
}

Добавлен еще один соответствующий метод, который используется методом call ():

public static double cosineSimForSentence(Word2Vec vectors, Collection<String> label1, Collection<String> label2) {
        try {
            return Transforms.cosineSim(vectors.getWordVectorsMean(label1), vector.getWordVectorsMean(label2));
        } catch (Exception e) {
            log.warn("OOV: " + label1.toString() + " " + label2.toString());
            //e.getMessage();
            //e.printStackTrace();
            return 0.0;
        }
    }

1 Ответ

0 голосов
/ 05 октября 2018

(Ответ обновлен для измененного вопроса.)

Как правило, вы должны профилировать код, прежде чем пытаться оптимизировать его, особенно если он довольно сложный.

Для многопоточности необходимо определить, какое изменяемое состояние разделяется между потоками.В идеале, насколько это возможно, прежде чем прибегать к блокировкам и параллельным структурам данных.Изменяемое состояние, которое содержится в одном потоке, не является проблемой как таковой.Неизменные значения - это здорово.

Я полагаю, что ничего, переданное вашей задаче, не будет изменено.Это сложно сказать.final на полях - хорошая идея.Коллекции могут быть помещены в неизменяемые обертки, хотя это не останавливает их изменение с помощью других ссылок и теперь показывает себя в статических типах.

Предполагая, что вы не разбиваете внутренний цикл, единственная общая изменяемая переменнаясостояние выглядит как similarities и содержащиеся в нем значения.

Вы можете или не можете обнаружить, что по-прежнему выполняете слишком много последовательных операций и вам нужно изменить similarities, чтобы стать параллельным

    ConcurrentMap<String, Set<String>> similarities = new ConcurrentHashMap<>();

get и put из similarities должны быть поточно-ориентированными.Я предлагаю всегда создавать Set.

        Set<String> similarityWords = similarities.getOrDefault(seed, new HashSet<>());

или

        Set<String> similarityWords = similarities.computeIfAbsent(seed, key -> new HashSet<>());

. Вы можете использовать потокобезопасный Set (например, с Collections.synchronizedSet), но я предлагаюудерживая соответствующую блокировку для всего внутреннего цикла.

synchronized (similarityWords) {
    ...
}

Если вы хотите создать similarityWords лениво, то это будет «веселее».

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...