Страницы

Поиск по вопросам

четверг, 7 марта 2019 г.

Многопоточный парсинг страниц

Для онлайн-игры пишу прогу, которая позволит получать полезные данные. Есть два метода, которые возвращают стоимость конкретного оружия на рынке для одной страны и для всех стран (74) вместе.
public void getCheapestWeapon(Weapon weapon) { //long result = 0; Map countryAndId = allCountries.getCountryAndId(); for (Map.Entry item : countryAndId.entrySet()) { //long start = System.currentTimeMillis(); getCheapestWeapon(item.getKey(), weapon); //long finish = System.currentTimeMillis(); //System.out.println(finish - start); //result += finish - start; } //System.out.println(result); }
public void getCheapestWeapon(String country, Weapon weapon) { long start = System.currentTimeMillis(); String link = MARKET_LINK + allCountries.getCountryId(country) + "/" + weapon.getPlaceOnMarket() + "/" + weapon.getQuality() + "/" + ADDITIONAL_LINK; try { Document page = Jsoup.connect(link) .userAgent("Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.106 Safari/537.36") .cookies(cookies) .timeout(1000) .get(); Elements table = page.getElementsByClass("price_sorted"); Element row = table.select("tr").first(); Elements columns = row.getElementsByTag("td"); Element priceCell = columns.get(3); String priceStr = priceCell.text(); double price = Double.parseDouble(priceStr.substring(0, priceStr.length() - 4)); System.out.println(country + " - " + price); } catch (IOException e) { e.printStackTrace(); } //long finish = System.currentTimeMillis(); //System.out.println(finish - start); }
Проблема в том, что при получении данных для всех стран, время на парсинг составляет в среднем 16-18 секунд что, согласитесь, очень много. Пробовал в первом методе засунуть getCheapestWeapon(item.getKey(), weapon) в отдельный поток. Ничего хорошего это не дало. Как можно реализовать одновременный парсинг всех 74-х страниц?


Ответ

В текущем виде (результаты работы getCheapestWeapon просто выводятся на консоль) проще всего использовать стандартный ExecutorService
public void getCheapestWeapon(Weapon weapon) { final int THREADS = 4; ExecutorService pool = Executors.newFixedThreadPool( THREADS );
Map countryAndId = allCountries.getCountryAndId(); for (Map.Entry item : countryAndId.entrySet()) { pool.execute( () -> getCheapestWeapon( item.getKey(), weapon ) ); }
pool.shutdown(); }
Если операция не разовая, то нужно вынести создание и остановку сервиса из метода. Т.к. основная задержка, скорее всего из-за сети (74 запроса, даже если пакет идет от клиента до сервера 50мс, съедят 7 секунд), число процессов в сервисе может превышать количество ядер (подберите экспериментально).
В качестве альтернативы, попробуйте получать у сервера больше данных меньшим количеством запросов, например убрав фильтр по странам, если вам нужна самая низкая цена.

Комментариев нет:

Отправить комментарий