Самый быстрый способ получить несколько веб-страниц на Java

Я пытаюсь написать быстрый парсер HTML, и сейчас я просто сосредотачиваюсь на максимальном увеличении пропускной способности без синтаксического анализа. Я кэшировал IP-адреса URL-адресов:

public class Data {
    private static final ArrayList sites = new ArrayList();
    public static final ArrayList URL_LIST = new ArrayList();
    public static final ArrayList ADDRESSES = new ArrayList();

    static{
        /*
        add all the URLs to the sites array list
        */

        // Resolve the DNS prior to testing the throughput 
        for(int i = 0; i < sites.size(); i++){

            try {
                URL tmp = new URL(sites.get(i));
                InetAddress address = InetAddress.getByName(tmp.getHost());
                ADDRESSES.add(address);
                URL_LIST.add(new URL("http", address.getHostAddress(), tmp.getPort(), tmp.getFile()));
                System.out.println(tmp.getHost() + ": " + address.getHostAddress());
            } catch (MalformedURLException e) {
            } catch (UnknownHostException e) {
            }
        }
    }
}

Следующим шагом было проверить скорость со 100 URL-адресами, загрузив их из Интернета, чтение первых 64 КБ и переход к следующему URL. Я создаю пул потоков из FetchTaskConsumer и пробовал запускать несколько потоков (от 16 до 64 на машине i7 Quad Core). Вот как выглядит каждый потребитель:

public class FetchTaskConsumer implements Runnable{
    private final CountDownLatch latch;
    private final int[] urlIndexes;
    public FetchTaskConsumer (int[] urlIndexes, CountDownLatch latch){
        this.urlIndexes = urlIndexes;
        this.latch = latch;
    }

    @Override
    public void run() {

        URLConnection resource;
        InputStream is = null;
        for(int i = 0; i < urlIndexes.length; i++)
        {
            int numBytes = 0;
            try {                   
                resource = Data.URL_LIST.get(urlIndexes[i]).openConnection();

                resource.setRequestProperty("User-Agent", "Mozilla/5.0");

                is = resource.getInputStream();

                while(is.read()!=-1 && numBytes < 65536 )
                {
                    numBytes++;
                }

            } catch (IOException e) {
                System.out.println("Fetch Exception: " + e.getMessage());
            } finally {

                System.out.println(numBytes + " bytes for url index " + urlIndexes[i] + "; remaining: " + remaining.decrementAndGet());
                if(is!=null){
                    try {
                        is.close();
                    } catch (IOException e1) {/*eat it*/}
                }
            }
        }

        latch.countDown();
    }
}

В лучшем случае я может пройти через 100 URL примерно за 30 секунд, но литература предполагает, что я должен быть в состоянии пройти через 300 150 URL в секунду. Обратите внимание, что у меня есть доступ к Gigabit Ethernet, хотя в настоящее время я запускаю тест дома на своем 20-мегабитном соединении ... в любом случае соединение никогда не используется полностью.

Я пробовал напрямую использовать Socket подключения, но я, должно быть, делаю что-то не так, потому что это еще медленнее! Есть предложения по увеличению пропускной способности?

PS
Я создаю пул потоков из FetchTaskConsumer и пробовал запускать несколько потоков (от 16 до 64 на машине i7 Quad Core). Вот как выглядит каждый потребитель:

public class FetchTaskConsumer implements Runnable{
    private final CountDownLatch latch;
    private final int[] urlIndexes;
    public FetchTaskConsumer (int[] urlIndexes, CountDownLatch latch){
        this.urlIndexes = urlIndexes;
        this.latch = latch;
    }

    @Override
    public void run() {

        URLConnection resource;
        InputStream is = null;
        for(int i = 0; i < urlIndexes.length; i++)
        {
            int numBytes = 0;
            try {                   
                resource = Data.URL_LIST.get(urlIndexes[i]).openConnection();

                resource.setRequestProperty("User-Agent", "Mozilla/5.0");

                is = resource.getInputStream();

                while(is.read()!=-1 && numBytes < 65536 )
                {
                    numBytes++;
                }

            } catch (IOException e) {
                System.out.println("Fetch Exception: " + e.getMessage());
            } finally {

                System.out.println(numBytes + " bytes for url index " + urlIndexes[i] + "; remaining: " + remaining.decrementAndGet());
                if(is!=null){
                    try {
                        is.close();
                    } catch (IOException e1) {/*eat it*/}
                }
            }
        }

        latch.countDown();
    }
}

В лучшем случае я может пройти через 100 URL примерно за 30 секунд, но литература предполагает, что я должен быть в состоянии пройти через 300 150 URL в секунду. Обратите внимание, что у меня есть доступ к Gigabit Ethernet, хотя в настоящее время я запускаю тест дома на своем 20-мегабитном соединении ... в любом случае соединение никогда не используется полностью.

Я пробовал напрямую использовать Socket подключения, но я должен делать что-то не так, потому что это еще медленнее! Есть предложения по увеличению пропускной способности?

PS
Я создаю пул потоков из FetchTaskConsumer и пробовал запускать несколько потоков (от 16 до 64 на машине i7 Quad Core). Вот как выглядит каждый потребитель:

public class FetchTaskConsumer implements Runnable{
    private final CountDownLatch latch;
    private final int[] urlIndexes;
    public FetchTaskConsumer (int[] urlIndexes, CountDownLatch latch){
        this.urlIndexes = urlIndexes;
        this.latch = latch;
    }

    @Override
    public void run() {

        URLConnection resource;
        InputStream is = null;
        for(int i = 0; i < urlIndexes.length; i++)
        {
            int numBytes = 0;
            try {                   
                resource = Data.URL_LIST.get(urlIndexes[i]).openConnection();

                resource.setRequestProperty("User-Agent", "Mozilla/5.0");

                is = resource.getInputStream();

                while(is.read()!=-1 && numBytes < 65536 )
                {
                    numBytes++;
                }

            } catch (IOException e) {
                System.out.println("Fetch Exception: " + e.getMessage());
            } finally {

                System.out.println(numBytes + " bytes for url index " + urlIndexes[i] + "; remaining: " + remaining.decrementAndGet());
                if(is!=null){
                    try {
                        is.close();
                    } catch (IOException e1) {/*eat it*/}
                }
            }
        }

        latch.countDown();
    }
}

В лучшем случае я может пройти через 100 URL примерно за 30 секунд, но литература предполагает, что я должен быть в состоянии пройти через 300 150 URL в секунду. Обратите внимание, что у меня есть доступ к Gigabit Ethernet, хотя в настоящее время я провожу тест дома на своем 20-мегабитном соединении ... в любом случае соединение никогда не используется полностью.

Я пробовал напрямую использовать Socket подключения, но я, должно быть, делаю что-то не так, потому что это еще медленнее! Есть предложения по увеличению пропускной способности?

PS
Я пробовал запустить несколько потоков (от 16 до 64 на машине с i7 Quad Core), вот как выглядит каждый потребитель:

public class FetchTaskConsumer implements Runnable{
    private final CountDownLatch latch;
    private final int[] urlIndexes;
    public FetchTaskConsumer (int[] urlIndexes, CountDownLatch latch){
        this.urlIndexes = urlIndexes;
        this.latch = latch;
    }

    @Override
    public void run() {

        URLConnection resource;
        InputStream is = null;
        for(int i = 0; i < urlIndexes.length; i++)
        {
            int numBytes = 0;
            try {                   
                resource = Data.URL_LIST.get(urlIndexes[i]).openConnection();

                resource.setRequestProperty("User-Agent", "Mozilla/5.0");

                is = resource.getInputStream();

                while(is.read()!=-1 && numBytes < 65536 )
                {
                    numBytes++;
                }

            } catch (IOException e) {
                System.out.println("Fetch Exception: " + e.getMessage());
            } finally {

                System.out.println(numBytes + " bytes for url index " + urlIndexes[i] + "; remaining: " + remaining.decrementAndGet());
                if(is!=null){
                    try {
                        is.close();
                    } catch (IOException e1) {/*eat it*/}
                }
            }
        }

        latch.countDown();
    }
}

В лучшем случае я могу просмотреть 100 URL примерно за 30 секунд, но в литературе говорится, что я должен иметь возможность проходить 300 150 URL-адресов в секунду. Обратите внимание, что у меня есть доступ к Gigabit Ethernet, хотя в настоящее время я запускаю тест дома на своем 20-мегабитном соединении ... в любом случае соединение никогда не используется полностью.

Я пробовал напрямую использовать Socket подключения, но я должен делать что-то не так, потому что это еще медленнее! Есть предложения по увеличению пропускной способности?

PS
Я пробовал запустить несколько потоков (от 16 до 64 на машине i7 Quad Core), вот как выглядит каждый потребитель:

public class FetchTaskConsumer implements Runnable{
    private final CountDownLatch latch;
    private final int[] urlIndexes;
    public FetchTaskConsumer (int[] urlIndexes, CountDownLatch latch){
        this.urlIndexes = urlIndexes;
        this.latch = latch;
    }

    @Override
    public void run() {

        URLConnection resource;
        InputStream is = null;
        for(int i = 0; i < urlIndexes.length; i++)
        {
            int numBytes = 0;
            try {                   
                resource = Data.URL_LIST.get(urlIndexes[i]).openConnection();

                resource.setRequestProperty("User-Agent", "Mozilla/5.0");

                is = resource.getInputStream();

                while(is.read()!=-1 && numBytes < 65536 )
                {
                    numBytes++;
                }

            } catch (IOException e) {
                System.out.println("Fetch Exception: " + e.getMessage());
            } finally {

                System.out.println(numBytes + " bytes for url index " + urlIndexes[i] + "; remaining: " + remaining.decrementAndGet());
                if(is!=null){
                    try {
                        is.close();
                    } catch (IOException e1) {/*eat it*/}
                }
            }
        }

        latch.countDown();
    }
}

В лучшем случае я могу просмотреть 100 URL примерно за 30 секунд, но в литературе говорится, что я должен иметь возможность проходить 300 150 URL-адресов в секунду. Обратите внимание, что у меня есть доступ к Gigabit Ethernet, хотя в настоящее время я провожу тест дома на своем 20-мегабитном соединении ... в любом случае соединение никогда не используется полностью.

Я пробовал напрямую использовать Socket подключения, но я, должно быть, делаю что-то не так, потому что это еще медленнее! Есть предложения по увеличению пропускной способности?

PS
но литература предполагает, что я должен иметь возможность просматривать 300 150 URL-адресов в секунду. Обратите внимание, что у меня есть доступ к Gigabit Ethernet, хотя в настоящее время я провожу тест дома на своем 20-мегабитном соединении ... в любом случае соединение никогда не используется полностью.

Я пробовал напрямую использовать Socket подключения, но я, должно быть, делаю что-то не так, потому что это еще медленнее! Есть предложения по увеличению пропускной способности?

PS
но литература предполагает, что я должен иметь возможность просматривать 300 150 URL-адресов в секунду. Обратите внимание, что у меня есть доступ к Gigabit Ethernet, хотя в настоящее время я запускаю тест дома на своем 20-мегабитном соединении ... в любом случае соединение никогда не используется полностью.

Я пробовал напрямую использовать Socket подключения, но я, должно быть, делаю что-то не так, потому что это еще медленнее! Есть предложения по увеличению пропускной способности?

PS
Я пробовал напрямую использовать соединения Socket , но я, должно быть, делаю что-то не так, потому что это еще медленнее! Есть предложения по увеличению пропускной способности?

PS
Я пробовал напрямую использовать соединения Socket , но я, должно быть, делаю что-то не так, потому что это еще медленнее! Есть предложения по увеличению пропускной способности?

PS
У меня есть список из примерно 1 миллиона популярных URL-адресов, поэтому я могу добавить больше URL-адресов, если 100 недостаточно для тестирования.

Обновление:
Литература, на которую я ссылаюсь , - это статьи, относящиеся к поисковый робот Najork, Наджорк утверждает:

Обработано 891 миллион URL за 17 дней
Это ~ 606 загрузок в секунду [на] 4 Серверы Compaq DS20E Alpha [с] 4 ГБ основной память [,] 650 ГБ на диске [и] 100 МБит / сек.
Интернет-провайдер Ethernet ограничивает пропускную способность до 160 Мбит / сек

Так что на самом деле это 150 страниц в секунду, а не 300. Мой компьютер - Core i7 с 4 ГБ ОЗУ, и я даже близко к этому не приблизился. Я не нашел ничего, что бы указывало на то, что они использовали в частности.

Обновление:
Хорошо, подведите итоги ... окончательные результаты уже есть! Оказывается, 100 URL-адресов - это слишком мало для теста. Я увеличил его до 1024 URL-адресов, 64 потока, я установил тайм-аут в 2 секунды для каждой выборки, и я смог получить до 21 страницы в секунду (на самом деле мое соединение составляет около 10,5 Мбит / с, поэтому 21 страница в секунду * 64 КБ на страницу составляет около 10,5 Мбит / с). Вот как выглядит сборщик:

public class FetchTask implements Runnable{
    private final int timeoutMS = 2000;
    private final CountDownLatch latch;
    private final int[] urlIndexes;
    public FetchTask(int[] urlIndexes, CountDownLatch latch){
        this.urlIndexes = urlIndexes;
        this.latch = latch;
    }

    @Override
    public void run() {

        URLConnection resource;
        InputStream is = null;
        for(int i = 0; i < urlIndexes.length; i++)
        {
            int numBytes = 0;
            try {                   
                resource = Data.URL_LIST.get(urlIndexes[i]).openConnection();

                resource.setConnectTimeout(timeoutMS);

                resource.setRequestProperty("User-Agent", "Mozilla/5.0");

                is = resource.getInputStream();

                while(is.read()!=-1 && numBytes < 65536 )
                {
                    numBytes++;
                }

            } catch (IOException e) {
                System.out.println("Fetch Exception: " + e.getMessage());
            } finally {

                System.out.println(numBytes + "," + urlIndexes[i] + "," + remaining.decrementAndGet());
                if(is!=null){
                    try {
                        is.close();
                    } catch (IOException e1) {/*eat it*/}
                }
            }
        }

        latch.countDown();
    }
}

7
задан Kiril 16 April 2011 в 23:56
поделиться