#java #multithreading
#java #многопоточность
Вопрос:
У меня есть большой набор слов, и мне нужно выполнить задачу для каждого отдельного слова. Я хочу сделать его многопоточным, чтобы увеличить скорость. В настоящее время я просто использую цикл foreach для перебора каждого элемента в списке. Что я хочу сделать, так это иметь 8 потоков, которые проверяют слово, которое я им даю, а затем записывают результат в файл.
В настоящее время я использую именно этот код:
public static void main(String[] args) {
System.setProperty("http.agent", "Chrome");
readWords();
Collections.shuffle(words);
words.forEach(word -> {
if (CheckValidity.checkValidity(word)) {
System.out.println(word);
try(PrintWriter writer = new PrintWriter(new FileWriter("output.txt",true)))
{
writer.printf("%srn", word);
} catch (IOException e) {
e.printStackTrace();
}
}
});
System.out.println("Done!");
}
Как бы я реализовал это в многопоточности? Я не смог найти никакой информации, которая имела бы смысл для меня, где я мог бы ввести значение в метод любого свободного потока. Извините, если это не совсем так, как работает многопоточность, я никогда раньше ничего не писал с более чем одним потоком, поэтому я не знаю, что возможно, а что нет.
Комментарии:
1. В этом случае узким местом могут быть операции ввода-вывода (запись в выходной файл). Вы (вероятно) не получите многого от многопоточности здесь.
2. Тем не менее, похоже, что вы пытаетесь заново изобрести ThreadPoolExecutor . JavaDocs этого класса (и те, на которые ссылаются оттуда) являются хорошей отправной точкой.
3. Или, возможно, параллельные потоки являются более подходящей абстракцией для вас — см. Описание пакета
java.util.stream
.4. хорошо, я проверю это. Узким местом определенно являются не операции ввода-вывода, а то, что отнимает больше всего времени, — это проверка слов с помощью API, поэтому время, необходимое для ответа веб-сайта, является узким местом.
5. В любом случае, почти наверняка быстрее сначала собрать допустимые слова в памяти и записывать в файл только после того, как вы закончите.
Ответ №1:
Самый быстрый способ распараллелить ваши вызовы CheckValidity
— использовать параллельный поток. Что-то вроде
public static void main(String[] args) {
List<String> words = readWords();
Collections.shuffle(words);
words.stream()
.unordered()
.parallel()
.filter(CheckValidity::checkValidity)
.forEach(word -> {
System.out.println(word);
try(PrintWriter writer = new PrintWriter(new FileWriter("output.txt",true)))
{
writer.printf("%srn", word);
} catch (IOException e) {
e.printStackTrace();
}
});
System.out.println("Done!");
}
Однако это не должно быть вашим производственным решением, если ваше приложение также выполняет другие действия параллельно, поскольку при этом внутренне используется общий ForkJoinPool, и блокирование этого с помощью операций, не связанных с процессором, может замедлить работу других частей вашего приложения (например, других параллельных потоков).
Для более надежного решения вам следует взглянуть на ThreadPoolExecutor, который позволяет создавать отдельные пулы потоков с определенными размерами, тайм-аутами и т.д.
Комментарии:
1. Спасибо, я смог использовать параллельный поток, который вы мне дали, и эту статью, чтобы ускорить работу моей программы примерно на 10 таймеров.