Domanda

Sto scrivendo un piccolo crawler che dovrebbe prendere un URL più volte, voglio che tutti i thread finiscano contemporaneamente (contemporaneamente).

Ho scritto un piccolo pezzo di codice che dovrebbe farlo.

import thread
from urllib2 import Request, urlopen, URLError, HTTPError


def getPAGE(FetchAddress):
    attempts = 0
    while attempts < 2:
        req = Request(FetchAddress, None)
        try:
            response = urlopen(req, timeout = 8) #fetching the url
            print "fetched url %s" % FetchAddress
        except HTTPError, e:
            print 'The server didn\'t do the request.'
            print 'Error code: ', str(e.code) + "  address: " + FetchAddress
            time.sleep(4)
            attempts += 1
        except URLError, e:
            print 'Failed to reach the server.'
            print 'Reason: ', str(e.reason) + "  address: " + FetchAddress
            time.sleep(4)
            attempts += 1
        except Exception, e:
            print 'Something bad happened in gatPAGE.'
            print 'Reason: ', str(e.reason) + "  address: " + FetchAddress
            time.sleep(4)
            attempts += 1
        else:
            try:
                return response.read()
            except:
                "there was an error with response.read()"
                return None
    return None

url = ("http://www.domain.com",)

for i in range(1,50):
    thread.start_new_thread(getPAGE, url)

Dai registri di Apache non sembra che i thread stiano funzionando contemporaneamente, c'è un piccolo divario tra le richieste, è quasi non rilevabile ma posso vedere che i thread non sono davvero paralleli.

Ho letto di Gil, c'è un modo per bypassarlo senza chiamare un codice C C ++? Non riesco davvero a capire come è possibile il threading con Gil? Python interpreta fondamentalmente il filo successivo non appena termina con quello precedente?

Grazie.

È stato utile?

Soluzione

Come fai notare, il Gil spesso impedisce ai fili di Python di correre in parallelo.

Tuttavia, non è sempre così. Un'eccezione è il codice legato a I/O. Quando un thread è in attesa di un completamento di una richiesta I/O, in genere avrebbe rilasciato il GIL prima di entrare nell'attesa. Ciò significa che altri thread possono fare progressi nel frattempo.

In generale, tuttavia, multiprocessing è la scommessa più sicura quando è richiesto il vero parallelismo.

Altri suggerimenti

Ho letto di Gil, c'è un modo per bypassarlo senza chiamare un codice C C ++?

Non proprio. Le funzioni chiamate tramite CTypes rilascerà il GIL per la durata di tali chiamate. Le funzioni che eseguono l'I/O bloccano lo rilascerà anche. Esistono altre situazioni simili, ma coinvolgono sempre un codice al di fuori del principale loop dell'interprete Python. Non puoi lasciar andare il Gil nel tuo codice Python.

Puoi usare un approccio come questo per creare tutti i thread, farli aspettare un oggetto condizionale e quindi iniziare a prendere a prendere l'URL "contemporaneamente":

#!/usr/bin/env python
import threading
import datetime
import urllib2

allgo = threading.Condition()

class ThreadClass(threading.Thread):
    def run(self):
        allgo.acquire()
        allgo.wait()
        allgo.release()
        print "%s at %s\n" % (self.getName(), datetime.datetime.now())
        url = urllib2.urlopen("http://www.ibm.com")

for i in range(50):
    t = ThreadClass()
    t.start()

allgo.acquire()
allgo.notify_all()
allgo.release()

Questo ti avvicinerebbe un po 'di più ad avere tutti i recuperati che si verificano allo stesso tempo, MA:

  • I pacchetti di rete che lasciano il computer passano lungo il filo Ethernet in sequenza, non allo stesso tempo,
  • Anche se hai 16+ core sulla tua macchina, è probabile che un router, un ponte, un modem o altre attrezzature tra la macchina e l'host web abbia meno core e possa serializzare le tue richieste,
  • Il server web da cui stai prendendo cose utilizzerà un accept() Chiama per rispondere alla tua richiesta. Per un comportamento corretto, che viene implementato utilizzando un blocco server-globale per garantire che un solo processo/thread di un server risponda alla query. Anche se alcune delle tue richieste arrivano al server contemporaneamente, questo causerà un certo serializzazione.

Probabilmente avrai le tue richieste sovrapposizione in misura maggiore (cioè altri a partire da un po 'di fine), ma non avrai mai tutte le tue richieste Inizia contemporaneamente sul server.

Puoi anche guardare cose come il futuro di Pypy in cui avremo la memoria di transizione software (eliminando così il GIL) Questo è tutto solo per la ricerca e la derisione intellettuale al momento, ma potrebbe diventare qualcosa di grande.

Se esegui il tuo codice con Jython o IronPython (e forse Pypy in futuro), funzionerà in parallelo

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top