Страницы

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

воскресенье, 12 января 2020 г.

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

#java #многопоточность #jsoup


Для онлайн-игры пишу прогу, которая позволит получать полезные данные.
Есть два метода, которые возвращают стоимость конкретного оружия на рынке для одной
страны и для всех стран (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-х страниц?
    


Ответы

Ответ 1



В текущем виде (результаты работы 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 секунд), число процессов в сервисе может превышать количество ядер (подберите экспериментально). В качестве альтернативы, попробуйте получать у сервера больше данных меньшим количеством запросов, например убрав фильтр по странам, если вам нужна самая низкая цена.

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

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