Domanda

Ho costruito un cingolato che doveva correre su circa pagine 5M (aumentando l'ID url) e quindi analizza le pagine che contengono informazioni' ho bisogno.

dopo l'utilizzo di un algoritmo che corrono sulla URL (200K) e salvati i buoni e cattivi risultati che ho scoperto che la sto sprecando un sacco di tempo. Ho potuto vedere che ci sono un paio di subtrahends ritorno che posso utilizzare per controllare il prossimo URL valido.

è possibile vedere i subtrahends abbastanza veloce (un po ex' dei pochi primi 'buoni ID') -

510000011 # +8
510000029 # +18
510000037 # +8
510000045 # +8
510000052 # +7
510000060 # +8
510000078 # +18
510000086 # +8
510000094 # +8
510000102 # +8
510000110 # etc'
510000128
510000136
510000144
510000151
510000169
510000177
510000185
510000193
510000201

Dopo la scansione di circa 200K di URL che mi ha dato solo 14K buoni risultati Sapevo che stavo sprecando il mio tempo e la necessità di ottimizzare, quindi corro alcune statistiche e costruito una funzione che controlla gli URL mentre aumenta l'ID con 8 \ 18 \ 17 \ 8 (in alto ritorno subtrahends) etc'.

questa è la funzione -

def checkNextID(ID):
    global numOfRuns, curRes, lastResult
    while ID < lastResult:
        try:
            numOfRuns += 1
            if numOfRuns % 10 == 0:
                time.sleep(3) # sleep every 10 iterations
            if isValid(ID + 8):
                parseHTML(curRes)
                checkNextID(ID + 8)
                return 0
            if isValid(ID + 18):
                parseHTML(curRes)
                checkNextID(ID + 18)
                return 0
            if isValid(ID + 7):
                parseHTML(curRes)
                checkNextID(ID + 7)
                return 0
            if isValid(ID + 17):
                parseHTML(curRes)
                checkNextID(ID + 17)
                return 0
            if isValid(ID+6):
                parseHTML(curRes)
                checkNextID(ID + 6)
                return 0
            if isValid(ID + 16):
                parseHTML(curRes)
                checkNextID(ID + 16)
                return 0
            else:
                checkNextID(ID + 1)
                return 0
        except Exception, e:
            print "somethin went wrong: " + str(e)

quello che è fondamentalmente fa è -checkNextID (ID) è sempre il primo ID So che contengono i dati meno 8 in modo che la prima iterazione corrisponderà il primo "se isValid" clausola (isValid (ID + 8) restituirà true) .

LASTRESULT è una variabile che salva l'ultima posizione nota url id, quindi dovremo correre fino numOfRuns è

isValid () è una funzione che ottiene un ID + uno dei subtrahends e restituisce true se l'URL contiene quello che mi serve e salva un oggetto zuppa del url del varibale globale denominato - ' curRes ', restituisce false se l'URL non contiene la necessità di dati I.

parseHTML è una funzione che ottiene l'oggetto zuppa (curRes), analizza i dati di cui ho bisogno e quindi salva i dati in un file CSV, quindi restituisce True.

se isValid () restituisce True, che chiameremo parseHTML () e quindi provare a controllare l'ID successivo + i subtrahends (chiamando checkNextID (ID + subtrahends), se nessuno di loro tornerà quello che sto cercando io aumentarlo con 1 e controllare di nuovo fino a quando troverò la prossima URL valido.

si può vedere il resto del codice qui

dopo l'esecuzione del codice che ho ottenuto circa 950 ~ buoni risultati e improvvisamente un'eccezione avevo sollevato -

"qualcosa è andato storto: la massima profondità di ricorsione superato durante la chiamata di un Python oggetto "

ho potuto vedere sul WireShark che la scipt bloccato su id -. 510.009.541 (ho iniziato la mia sceneggiatura con 510.000.003), lo script ha tentato di ottenere l'url con quel ID un paio di volte prima che ho notato l'errore e si è fermato

I è stato davvero emozionante vedere che ho ottenuto gli stessi risultati, ma 25x-40x volte più veloce il mio vecchio copione, con un minor numero di richieste HTTP, è molto preciso, ho perso solo 1 risultato per 1000 buoni risultati, che è trovare da me, è impossibile rum 5M volte, ho avuto il mio vecchio script in esecuzione per 30 ore ed ho ottenuto risultati 14-15K quando il mio nuovo script mi ??ha dato 960 ~ risultati in 5-10 minuti.

ho letto sui limiti dello stack, ma ci deve essere una soluzione per l'algoritmo che sto cercando di implementare in Python (non posso tornare al mio vecchio "algoritmo" , non sarà mai fine).

Grazie!

È stato utile?

Soluzione

this turns the recursion in to a loop:

def checkNextID(ID):
    global numOfRuns, curRes, lastResult
    while ID < lastResult:
        try:
            numOfRuns += 1
            if numOfRuns % 10 == 0:
                time.sleep(3) # sleep every 10 iterations
            if isValid(ID + 8):
                parseHTML(curRes)
                ID = ID + 8
            elif isValid(ID + 18):
                parseHTML(curRes)
                ID = ID + 18
            elif isValid(ID + 7):
                parseHTML(curRes)
                ID = ID + 7
            elif isValid(ID + 17):
                parseHTML(curRes)
                ID = ID + 17
            elif isValid(ID+6):
                parseHTML(curRes)
                ID = ID + 6
            elif isValid(ID + 16):
                parseHTML(curRes)
                ID = ID + 16
            else:
                ID = ID + 1
        except Exception, e:
            print "somethin went wrong: " + str(e)

Altri suggerimenti

Python don't have a great support for recursion because of it's lack of TRE (Tail Recursion Elimination).

This means that each call to your recursive function will create a function call stack and because there is a limit of stack depth (by default is 1000) that you can check out by sys.getrecursionlimit (of course you can change it using sys.setrecursionlimit but it's not recommended) your program will end up by crashing when it hits this limit.

As other answer has already give you a much nicer way for how to solve this in your case (which is to replace recursion by simple loop) there is another solution if you still want to use recursion which is to use one of the many recipes of implementing TRE in python like this one.

N.B: My answer is meant to give you more insight on why you get the error, and I'm not advising you to use the TRE as i already explained because in your case a loop will be much better and easy to read.

You can increase the capacity of the stack by the following :

import sys
sys.setrecursionlimit(10000)

Instead of doing recursion, the parts of the code with checkNextID(ID + 18) and similar could be replaced with ID+=18, and then if you remove all instances of return 0, then it should do the same thing but as a simple loop. You should then put a return 0 at the end and make your variables non-global.

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