Jak mogę przyspieszyć pobieranie stron za pomocą urllib2 w Pythonie?

Mam skrypt, który pobiera kilka stron internetowych i przetwarza informacje.

(Przykład można zobaczyć na http://bluedevilbooks.com/search/?DEPT=MATH&CLASS=103&SEC=01 )

Uruchomiłem cProfile na nim, i jak założyłem, urlopen zajmuje dużo czasu. Czy istnieje sposób na szybsze pobieranie stron? Albo sposób na pobranie kilku stron naraz? Zrobię wszystko, co jest najprostsze, ponieważ jestem nowy w Pythonie i tworzeniu stron internetowych.

Z góry dzięki! :)

UPDATE: mam funkcję wywołane fetchURLs(), którego używam do tworzenia tablicy adresów URL, których potrzebuję więc coś w stylu urls = fetchURLS().Adresy URL to wszystkie pliki XML z API Amazon i eBay (co myli mnie, dlaczego ładowanie trwa tak długo, może mój webhost jest powolny?)

To, co muszę zrobić, to załadować każdy adres URL, odczytać każdą stronę i wysłać te dane do innej części skryptu, która będzie analizować i wyświetlać dane.

Zauważ, że nie mogę zrobić tej drugiej części, dopóki wszystkie strony nie zostaną pobrane, to jest mój problem jest.

Poza tym mój host ogranicza mnie do 25 procesów na raz, więc cokolwiek jest najłatwiejsze na serwerze byłoby miłe:)


Oto czas:

Sun Aug 15 20:51:22 2010    prof

         211352 function calls (209292 primitive calls) in 22.254 CPU seconds

   Ordered by: internal time
   List reduced from 404 to 10 due to restriction <10>

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
       10   18.056    1.806   18.056    1.806 {_socket.getaddrinfo}
     4991    2.730    0.001    2.730    0.001 {method 'recv' of '_socket.socket' objects}
       10    0.490    0.049    0.490    0.049 {method 'connect' of '_socket.socket' objects}
     2415    0.079    0.000    0.079    0.000 {method 'translate' of 'unicode' objects}
       12    0.061    0.005    0.745    0.062 /usr/local/lib/python2.6/HTMLParser.py:132(goahead)
     3428    0.060    0.000    0.202    0.000 /usr/local/lib/python2.6/site-packages/BeautifulSoup.py:1306(endData)
     1698    0.055    0.000    0.068    0.000 /usr/local/lib/python2.6/site-packages/BeautifulSoup.py:1351(_smartPop)
     4125    0.053    0.000    0.056    0.000 /usr/local/lib/python2.6/site-packages/BeautifulSoup.py:118(setup)
     1698    0.042    0.000    0.358    0.000 /usr/local/lib/python2.6/HTMLParser.py:224(parse_starttag)
     1698    0.042    0.000    0.275    0.000 /usr/local/lib/python2.6/site-packages/BeautifulSoup.py:1397(unknown_starttag)
Author: Parker, 2010-08-16

10 answers

EDIT : rozszerzam odpowiedź o bardziej dopracowany przykład. Znalazłem wiele wrogości i dezinformacji w tym poście dotyczącym wątku V. S. async I / O. dlatego dodaję również więcej argumentów, aby obalić pewne nieprawidłowe twierdzenie. Mam nadzieję, że pomoże to ludziom wybrać odpowiednie narzędzie do właściwej pracy.

To pytanie sprzed 3 dni.

Python urllib2.otwarcie jest powolne, potrzeba lepszego sposobu na odczytanie kilku adresów URL-przepełnienie stosu Python urllib2urlopen() jest powolne, wymaga lepszego sposobu odczytu kilku adresów URL

Poleruję kod, aby pokazać, jak pobrać kilka stron jednocześnie za pomocą wątków.

import time
import threading
import Queue

# utility - spawn a thread to execute target for each args
def run_parallel_in_threads(target, args_list):
    result = Queue.Queue()
    # wrapper to collect return value in a Queue
    def task_wrapper(*args):
        result.put(target(*args))
    threads = [threading.Thread(target=task_wrapper, args=args) for args in args_list]
    for t in threads:
        t.start()
    for t in threads:
        t.join()
    return result

def dummy_task(n):
    for i in xrange(n):
        time.sleep(0.1)
    return n

# below is the application code
urls = [
    ('http://www.google.com/',),
    ('http://www.lycos.com/',),
    ('http://www.bing.com/',),
    ('http://www.altavista.com/',),
    ('http://achewood.com/',),
]

def fetch(url):
    return urllib2.urlopen(url).read()

run_parallel_in_threads(fetch, urls)

Jak widać, kod specyficzny dla aplikacji ma tylko 3 linie, które mogą być zwinięte w 1 linię, jeśli jesteś agresywny. Nie sądzę, aby ktokolwiek mógł uzasadnić swoje twierdzenie, że jest to skomplikowane i niemożliwe do utrzymania.

Niestety większość innych zamieszczonych tu kodów wątkowych ma pewne wady. Wielu z nich tak aktywne ankiety, aby czekać na zakończenie kodu. join() to lepszy sposób na synchronizację kodu. Myślę, że ten kod poprawił się na wszystkich przykładach wątków do tej pory.

Keep-alive connection

Sugestia Wolpha dotycząca używania połączenia keep-alive może być bardzo przydatna, jeśli wszystkie adresy URL wskazują na ten sam serwer.

Twisted

Aaron Gallagher jest fanem twisted frameworku i jest wrogo nastawiony do wszystkich osób, które sugerują wątek. Niestety dużo jego twierdzenia są dezinformacją. Na przykład powiedział " -1 za sugerowanie wątków. Jest to związane z IO; wątki są tutaj bezużyteczne."Jest to sprzeczne z dowodami, ponieważ zarówno Nick T, jak I ja zademonstrowaliśmy zysk prędkości z używanego wątku. W rzeczywistości aplikacje związane z I / O mają najwięcej korzyści z używania wątku Pythona(V. S. brak zysku w aplikacji związanej z procesorem). Błędna krytyka Aarona na temat thread pokazuje, że jest raczej zdezorientowany co do programowania równoległego w ogóle.

Właściwe narzędzie dla właściwych job

Jestem świadomy problemów związanych z programowaniem równoległym za pomocą wątków, Pythona, asynchronicznych We / Wy i tak dalej. Każde narzędzie ma swoje wady i zalety. Dla każdej sytuacji istnieje odpowiednie narzędzie. Nie jestem przeciwko twisted (choć sam nie wdrożyłem). Ale nie wierzę, że możemy powiedzieć, że nić jest zła, a skręcona jest dobra we wszystkich sytuacjach.

Na przykład, jeśli op wymaga równoległego pobierania 10 000 stron internetowych, preferowane będą wejścia/Wyjścia asynchroniczne. Threading nie będzie odpowiedni (chyba, że z Pythonem bez stosu).

Sprzeciw Aarona wobec wątków to głównie uogólnienia. Nie dostrzega, że jest to trywialne zadanie równoległe. Każde zadanie jest niezależne i nie dzieli się zasobami. Więc większość jego ataku nie ma zastosowania.

Ponieważ mój kod nie ma zewnętrznej zależności, nazwę Go właściwym narzędziem do właściwej pracy.

Wydajność

Myślę, że większość ludzi zgodzi się, że wykonanie tego zadania jest w dużej mierze zależy od kodu sieciowego i zewnętrznego serwera, gdzie wydajność kodu platformy powinna mieć znikomy wpływ. Jednak Benchmark Aarona pokazuje 50% wzrost prędkości w stosunku do kodu gwintowanego. Myślę, że należy zareagować na ten pozorny wzrost prędkości.

W kodzie Nicka jest oczywisty błąd, który spowodował nieefektywność. Ale jak wytłumaczysz przyrost prędkości 233ms w stosunku do mojego kodu? Myślę, że nawet pokręceni fani powstrzymają się od wyciągania wniosków, aby przypisać to za sprawność skręcania. Istnieje przecież ogromna ilość zmiennych poza kodem systemowym, takich jak wydajność zdalnego serwera, sieć, buforowanie i implementacja różnicy między urllib2 a twisted web client i tak dalej.

Aby upewnić się, że wątek Pythona nie spowoduje ogromnej nieefektywności, robię szybki benchmark, aby wywołać 5 wątków, a następnie 500 wątków. Całkiem wygodnie mi powiedzieć, że narzut 5 wątku jest znikomy i nie da się wyjaśnić różnica prędkości 233ms.

In [274]: %time run_parallel_in_threads(dummy_task, [(0,)]*5)
CPU times: user 0.00 s, sys: 0.00 s, total: 0.00 s
Wall time: 0.00 s
Out[275]: <Queue.Queue instance at 0x038B2878>

In [276]: %time run_parallel_in_threads(dummy_task, [(0,)]*500)
CPU times: user 0.16 s, sys: 0.00 s, total: 0.16 s
Wall time: 0.16 s

In [278]: %time run_parallel_in_threads(dummy_task, [(10,)]*500)
CPU times: user 1.13 s, sys: 0.00 s, total: 1.13 s
Wall time: 1.13 s       <<<<<<<< This means 0.13s of overhead

Dalsze testy na moim równoległym pobieraniu pokazują ogromną zmienność czasu odpowiedzi w 17 biegach. (Niestety nie mam twisted aby zweryfikować kod Aarona).

0.75 s
0.38 s
0.59 s
0.38 s
0.62 s
1.50 s
0.49 s
0.36 s
0.95 s
0.43 s
0.61 s
0.81 s
0.46 s
1.21 s
2.87 s
1.04 s
1.72 s

Moje testy nie potwierdzają wniosku Aarona, że threading jest konsekwentnie wolniejszy niż asynchroniczne We/Wy o mierzalny margines. Biorąc pod uwagę liczbę zmiennych, muszę powiedzieć, że nie jest to prawidłowy test do pomiaru systematycznej różnicy wydajności między asynchronicznymi We/Wy i gwintowanie.

 24
Author: Wai Yip Tung,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:54:46

Użyj twisted ! To sprawia, że takie rzeczy są absurdalnie łatwe w porównaniu do, powiedzmy, używania wątków.

from twisted.internet import defer, reactor
from twisted.web.client import getPage
import time

def processPage(page, url):
    # do somewthing here.
    return url, len(page)

def printResults(result):
    for success, value in result:
        if success:
            print 'Success:', value
        else:
            print 'Failure:', value.getErrorMessage()

def printDelta(_, start):
    delta = time.time() - start
    print 'ran in %0.3fs' % (delta,)
    return delta

urls = [
    'http://www.google.com/',
    'http://www.lycos.com/',
    'http://www.bing.com/',
    'http://www.altavista.com/',
    'http://achewood.com/',
]

def fetchURLs():
    callbacks = []
    for url in urls:
        d = getPage(url)
        d.addCallback(processPage, url)
        callbacks.append(d)

    callbacks = defer.DeferredList(callbacks)
    callbacks.addCallback(printResults)
    return callbacks

@defer.inlineCallbacks
def main():
    times = []
    for x in xrange(5):
        d = fetchURLs()
        d.addCallback(printDelta, time.time())
        times.append((yield d))
    print 'avg time: %0.3fs' % (sum(times) / len(times),)

reactor.callWhenRunning(main)
reactor.run()

Ten kod działa również lepiej niż jakiekolwiek inne opublikowane rozwiązania (edytowane po zamknięciu niektórych rzeczy, które używały dużej przepustowości):

Success: ('http://www.google.com/', 8135)
Success: ('http://www.lycos.com/', 29996)
Success: ('http://www.bing.com/', 28611)
Success: ('http://www.altavista.com/', 8378)
Success: ('http://achewood.com/', 15043)
ran in 0.518s
Success: ('http://www.google.com/', 8135)
Success: ('http://www.lycos.com/', 30349)
Success: ('http://www.bing.com/', 28611)
Success: ('http://www.altavista.com/', 8378)
Success: ('http://achewood.com/', 15043)
ran in 0.461s
Success: ('http://www.google.com/', 8135)
Success: ('http://www.lycos.com/', 30033)
Success: ('http://www.bing.com/', 28611)
Success: ('http://www.altavista.com/', 8378)
Success: ('http://achewood.com/', 15043)
ran in 0.435s
Success: ('http://www.google.com/', 8117)
Success: ('http://www.lycos.com/', 30349)
Success: ('http://www.bing.com/', 28611)
Success: ('http://www.altavista.com/', 8378)
Success: ('http://achewood.com/', 15043)
ran in 0.449s
Success: ('http://www.google.com/', 8135)
Success: ('http://www.lycos.com/', 30349)
Success: ('http://www.bing.com/', 28611)
Success: ('http://www.altavista.com/', 8378)
Success: ('http://achewood.com/', 15043)
ran in 0.547s
avg time: 0.482s

I używając kodu Nicka T, można też dać średnią z pięciu i lepiej pokazać wyjście:

Starting threaded reads:
...took 1.921520 seconds ([8117, 30070, 15043, 8386, 28611])
Starting threaded reads:
...took 1.779461 seconds ([8135, 15043, 8386, 30349, 28611])
Starting threaded reads:
...took 1.756968 seconds ([8135, 8386, 15043, 30349, 28611])
Starting threaded reads:
...took 1.762956 seconds ([8386, 8135, 15043, 29996, 28611])
Starting threaded reads:
...took 1.654377 seconds ([8117, 30349, 15043, 8386, 28611])
avg time: 1.775s

Starting sequential reads:
...took 1.389803 seconds ([8135, 30147, 28611, 8386, 15043])
Starting sequential reads:
...took 1.457451 seconds ([8135, 30051, 28611, 8386, 15043])
Starting sequential reads:
...took 1.432214 seconds ([8135, 29996, 28611, 8386, 15043])
Starting sequential reads:
...took 1.447866 seconds ([8117, 30028, 28611, 8386, 15043])
Starting sequential reads:
...took 1.468946 seconds ([8153, 30051, 28611, 8386, 15043])
avg time: 1.439s

I używając kodu Wai Yip Tung:

Fetched 8117 from http://www.google.com/
Fetched 28611 from http://www.bing.com/
Fetched 8386 from http://www.altavista.com/
Fetched 30051 from http://www.lycos.com/
Fetched 15043 from http://achewood.com/
done in 0.704s
Fetched 8117 from http://www.google.com/
Fetched 28611 from http://www.bing.com/
Fetched 8386 from http://www.altavista.com/
Fetched 30114 from http://www.lycos.com/
Fetched 15043 from http://achewood.com/
done in 0.845s
Fetched 8153 from http://www.google.com/
Fetched 28611 from http://www.bing.com/
Fetched 8386 from http://www.altavista.com/
Fetched 30070 from http://www.lycos.com/
Fetched 15043 from http://achewood.com/
done in 0.689s
Fetched 8117 from http://www.google.com/
Fetched 28611 from http://www.bing.com/
Fetched 8386 from http://www.altavista.com/
Fetched 30114 from http://www.lycos.com/
Fetched 15043 from http://achewood.com/
done in 0.647s
Fetched 8135 from http://www.google.com/
Fetched 28611 from http://www.bing.com/
Fetched 8386 from http://www.altavista.com/
Fetched 30349 from http://www.lycos.com/
Fetched 15043 from http://achewood.com/
done in 0.693s
avg time: 0.715s

I ' ve gotta say, I do like that the sequential dla mnie lepsze .

 18
Author: habnabit,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-08-16 07:38:43

Oto przykład użycia Pythona Threads. Inne przykłady wątków uruchamiają wątek na adres url, co nie jest zbyt przyjaznym zachowaniem, jeśli powoduje zbyt wiele trafień dla serwera (na przykład często zdarza się, że pająki mają wiele adresów URL na tym samym hoście) {]}

from threading import Thread
from urllib2 import urlopen
from time import time, sleep

WORKERS=1
urls = ['http://docs.python.org/library/threading.html',
        'http://docs.python.org/library/thread.html',
        'http://docs.python.org/library/multiprocessing.html',
        'http://docs.python.org/howto/urllib2.html']*10
results = []

class Worker(Thread):
    def run(self):
        while urls:
            url = urls.pop()
            results.append((url, urlopen(url).read()))

start = time()
threads = [Worker() for i in range(WORKERS)]
any(t.start() for t in threads)

while len(results)<40:
    sleep(0.1)
print time()-start

Uwaga: podane czasy dotyczą 40 adresów URL i w dużej mierze zależą od szybkości połączenia internetowego i opóźnienia na serwerze. Będąc w Australii, mój ping wynosi > 300ms

Z WORKERS=1 zajęło 86 seconds to run
Z WORKERS=4 bieganie zajęło 23 sekundy
z WORKERS=10 to trwało 10 sekund, aby uruchomić

Więc pobieranie 10 wątków jest 8,6 razy szybsze niż pojedynczy wątek.

Oto ulepszona wersja, która używa kolejki. Jest co najmniej kilka zalet.
1. Adresy URL są wymagane w kolejności, w jakiej pojawiają się na liście
2. Można użyć q.join() do wykrycia, kiedy wszystkie żądania zostały zakończone
3. Wyniki są przechowywane w tej samej kolejności Co adres url lista

from threading import Thread
from urllib2 import urlopen
from time import time, sleep
from Queue import Queue

WORKERS=10
urls = ['http://docs.python.org/library/threading.html',
        'http://docs.python.org/library/thread.html',
        'http://docs.python.org/library/multiprocessing.html',
        'http://docs.python.org/howto/urllib2.html']*10
results = [None]*len(urls)

def worker():
    while True:
        i, url = q.get()
        # print "requesting ", i, url       # if you want to see what's going on
        results[i]=urlopen(url).read()
        q.task_done()

start = time()
q = Queue()
for i in range(WORKERS):
    t=Thread(target=worker)
    t.daemon = True
    t.start()

for i,url in enumerate(urls):
    q.put((i,url))
q.join()
print time()-start
 5
Author: John La Rooy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-08-16 23:30:20

Rzeczywiste oczekiwanie prawdopodobnie nie jest w urllib2, ale w serwerze i / lub twoim połączeniu sieciowym z serwerem.

Są dwa sposoby na przyspieszenie tego.
  1. utrzymuj połączenie przy życiu (zobacz to pytanie, Jak to zrobić: Python urllib2 z keep alive )
  2. Użyj wielu połączeń, możesz użyć wątków lub podejścia asynchronicznego, jak zasugerował Aaron Gallagher. W tym celu po prostu użyj dowolnego przykładu wątków i powinieneś zrobić dobrze :) Możesz również użyć multiprocessing lib do Ułatw to sobie.
 2
Author: Wolph,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:47:22

Większość odpowiedzi skupiała się na pobieraniu wielu stron z różnych serwerów w tym samym czasie (threading) ale nie przy ponownym użyciu już otwarte połączenie HTTP. Jeśli OP składa wiele żądań na ten sam serwer/stronę.

W urlib2 tworzone jest oddzielne połączenie z każdym żądaniem, które wpływa na wydajność i w rezultacie na wolniejsze tempo pobierania stron. urllib3 rozwiązuje ten problem za pomocą puli połączeń. Możesz przeczytać więcej tutaj urllib3 [również thread-safe]

Istnieje również Requests biblioteka HTTP, która używa urllib3

To w połączeniu z threadingiem powinno zwiększyć szybkość pobierania stron

 2
Author: Skillachie,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-12-30 13:58:28

Obecnie istnieje znakomita lib Pythona, która robi to za Ciebie o nazwie requests .

Użyj standardowego api żądań, jeśli chcesz rozwiązania opartego na wątkach lub asynchronicznego api (używając gevent pod maską), jeśli chcesz rozwiązania opartego na nieblokujących IO.

 1
Author: Piotr Dobrogost,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-01-27 13:31:00

Odkąd to pytanie zostało opublikowane, wygląda na to, że dostępna jest abstrakcja wyższego poziomu, ThreadPoolExecutor:

Https://docs.python.org/3/library/concurrent.futures.html#threadpoolexecutor-example

Przykład stamtąd wklejony tutaj dla wygody:

import concurrent.futures
import urllib.request

URLS = ['http://www.foxnews.com/',
        'http://www.cnn.com/',
        'http://europe.wsj.com/',
        'http://www.bbc.co.uk/',
        'http://some-made-up-domain.com/']

# Retrieve a single page and report the url and contents
def load_url(url, timeout):
    with urllib.request.urlopen(url, timeout=timeout) as conn:
        return conn.read()

# We can use a with statement to ensure threads are cleaned up promptly
with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor:
    # Start the load operations and mark each future with its URL
    future_to_url = {executor.submit(load_url, url, 60): url for url in URLS}
    for future in concurrent.futures.as_completed(future_to_url):
        url = future_to_url[future]
        try:
            data = future.result()
        except Exception as exc:
            print('%r generated an exception: %s' % (url, exc))
        else:
            print('%r page is %d bytes' % (url, len(data)))

Jest też {[2] } co chyba ułatwia kod: https://docs.python.org/3/library/concurrent.futures.html#concurrent.futures.Executor.map

 1
Author: Milimetric,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-12-11 17:32:57

Pobieranie stron internetowych oczywiście zajmie trochę czasu, ponieważ nie masz dostępu do niczego lokalnego. Jeśli masz kilka do uzyskania dostępu, możesz użyć threading Moduł do uruchomienia kilku na raz.

Oto bardzo prymitywny przykład

import threading
import urllib2
import time

urls = ['http://docs.python.org/library/threading.html',
        'http://docs.python.org/library/thread.html',
        'http://docs.python.org/library/multiprocessing.html',
        'http://docs.python.org/howto/urllib2.html']
data1 = []
data2 = []

class PageFetch(threading.Thread):
    def __init__(self, url, datadump):
        self.url = url
        self.datadump = datadump
        threading.Thread.__init__(self)
    def run(self):
        page = urllib2.urlopen(self.url)
        self.datadump.append(page.read()) # don't do it like this.

print "Starting threaded reads:"
start = time.clock()
for url in urls:
    PageFetch(url, data2).start()
while len(data2) < len(urls): pass # don't do this either.
print "...took %f seconds" % (time.clock() - start)

print "Starting sequential reads:"
start = time.clock()
for url in urls:
    page = urllib2.urlopen(url)
    data1.append(page.read())
print "...took %f seconds" % (time.clock() - start)

for i,x in enumerate(data1):
    print len(data1[i]), len(data2[i])

To było wyjście kiedy go uruchomiłem:

Starting threaded reads:
...took 2.035579 seconds
Starting sequential reads:
...took 4.307102 seconds
73127 19923
19923 59366
361483 73127
59366 361483

Pobieranie danych z wątku przez dodanie do listy jest prawdopodobnie nierozsądne (Kolejka byłaby lepsza), ale pokazuje to, że jest różnica.

 0
Author: Nick T,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-08-16 02:50:53

Oto standardowe rozwiązanie biblioteki. Nie jest tak szybki, ale zużywa mniej pamięci niż rozwiązania gwintowane.

try:
    from http.client import HTTPConnection, HTTPSConnection
except ImportError:
    from httplib import HTTPConnection, HTTPSConnection
connections = []
results = []

for url in urls:
    scheme, _, host, path = url.split('/', 3)
    h = (HTTPConnection if scheme == 'http:' else HTTPSConnection)(host)
    h.request('GET', '/' + path)
    connections.append(h)
for h in connections:
    results.append(h.getresponse().read())

Ponadto, jeśli większość twoich żądań dotyczy tego samego hosta, ponowne użycie tego samego połączenia http prawdopodobnie pomogłoby bardziej niż robienie rzeczy równolegle.

 0
Author: Collin Anderson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-11-23 16:02:36

Proszę znaleźć Python network benchmark script do identyfikacji powolności pojedynczego połączenia:

"""Python network test."""
from socket import create_connection
from time import time

try:
    from urllib2 import urlopen
except ImportError:
    from urllib.request import urlopen

TIC = time()
create_connection(('216.58.194.174', 80))
print('Duration socket IP connection (s): {:.2f}'.format(time() - TIC))

TIC = time()
create_connection(('google.com', 80))
print('Duration socket DNS connection (s): {:.2f}'.format(time() - TIC))

TIC = time()
urlopen('http://216.58.194.174')
print('Duration urlopen IP connection (s): {:.2f}'.format(time() - TIC))

TIC = time()
urlopen('http://google.com')
print('Duration urlopen DNS connection (s): {:.2f}'.format(time() - TIC))

I przykład wyników z Pythonem 3.6:

Duration socket IP connection (s): 0.02
Duration socket DNS connection (s): 75.51
Duration urlopen IP connection (s): 75.88
Duration urlopen DNS connection (s): 151.42

Python 2.7.13 ma bardzo podobne wyniki.

W tym przypadku powolność DNS i urlopen jest łatwa do zidentyfikowania.

 0
Author: Velizar VESSELINOV,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-01 18:28:13