Come posso eseguire il multiprocesso del mio programma?

2

Ho scritto un programma che raschia i siti internet. È piuttosto stravagante perché elabora i collegamenti uno per uno.

Con il fattore limitante della velocità di internet, il processo è piuttosto lento.

Mi chiedo, come posso renderlo multiprocesso? I moduli di Python sono confusi. Non conosco la differenza tra sottoprocesso e multiprocesso. Ho sentito che il multiprocessing è difficile e inefficace a causa del GIL da python 2.x. Sto usando Python 3.2, quindi mi chiedo se le cose sono state migliorate.

    
posta lamwaiman1988 21.08.2012 - 11:24
fonte

3 risposte

9

Prima di tutto: il GIL non si applica alla multielaborazione, solo al threading, e non è un grosso problema come sembra che la gente lo capisca. Per uno, quando si utilizza un I / O di rete o di file, il blocco viene rilasciato, quindi tutto ciò che raschia i siti Web non è probabile che veda i colli di bottiglia delle prestazioni a causa del GIL.

Il modulo subprocess ha lo scopo di chiamare i processi arbitrari dal tuo programma , praticamente tutto ciò che puoi eseguire dalla riga di comando sulla macchina è un gioco leale per questo modulo.

Il multiprocessing modulo d'altra parte, ha lo scopo di rendere il lavoro di distribuzione su più processi Python come facile come usare thread per lo stesso tipo di lavoro. È il modulo che dovresti esaminare se desideri implementare lo scraping del sito distribuito utilizzando più processi.

Detto questo, perché non dai un'occhiata a Scrapy , invece:

Scrapy is a fast high-level screen scraping and web crawling framework, used to crawl websites and extract structured data from their pages. It can be used for a wide range of purposes, from data mining to monitoring and automated testing.

Scrapy utilizza un approccio al ciclo basato sugli eventi anziché utilizzare più thread o processi per risolvere il problema di "I / O di rete lento". Un ciclo di eventi commuta tra diverse attività nel programma quando i dati di rete (o qualsiasi altro I / O) sono in sospeso. Anziché attendere che i dati di rete entrino prima di continuare, un ciclo di eventi passa a un'attività diversa invece di lasciarlo al sistema operativo per informare il programma quando i dati di rete sono arrivati.

Se Scrapy non si adatta alle tue esigenze specifiche, puoi comunque utilizzare lo stesso trucco. Dai uno sguardo ai seguenti framework per aiutarti a fare la stessa cosa nel tuo programma:

Scrapy usa twisted , se questo fa la differenza per te.

    
risposta data 21.08.2012 - 11:44
fonte
0

Se hai una lista di siti da raggirare, la tua risposta potrebbe essere semplice come suddividerla in due elenchi ed eseguire due copie del tuo programma python, uno contro ogni lista. Se il programma normalmente trascorre la maggior parte del tempo in attesa che il sito risponda, vedrai una accelerazione. Se, d'altra parte, la velocità del tuo programma è limitata dalla larghezza di banda della tua rete, o quanto velocemente il tuo programma può elaborare ogni sito, vedrai un rallentamento. Quindi cronometrare il programma in esecuzione con un'istanza (forse e tempo medio per 100 siti), quindi passare due istanze, quindi tre ... Troverete un punto debole in cui più o meno istanze rallentano il programma.

La multiprocessing è molto difficile dove i due processi condividono i dati. Assicurati che non sia necessario condividere dati o comunicare tra loro e la multielaborazione è facile. Certo, essere davvero sicuri che non ci siano dipendenze è difficile. : -)

    
risposta data 21.08.2012 - 15:51
fonte
0

Molti dei suggerimenti forniti sono per python 2.x.

Ho scoperto che python 3.x fornisce un multiprocesso facile da fare, ovvero concurrent.futures modulo

Il seguente snippet dimostra come farlo facilmente:

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/']

def load_url(url, timeout):
    return urllib.request.urlopen(url, timeout=timeout).read()

with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor:
    future_to_url = dict((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]
        if future.exception() is not None:
            print('%r generated an exception: %s' % (url,
                                                     future.exception()))
        else:
            print('%r page is %d bytes' % (url, len(future.result())))
    
risposta data 24.08.2012 - 08:33
fonte

Leggi altre domande sui tag