2010-09-08 7 views
1

Dans le code ci-dessous, j'utilise mutli-threading ou multi-process pour l'extraction depuis url. Je pense que les pools seraient idéaux, Quelqu'un peut-il aider à suggérer la solution ..python multi-threading/code multi-processus

Idée: pool thread/processus, collecter des données ... ma préférence est le processus sur le fil, mais pas sûr.

import urllib 

URL = "http://download.finance.yahoo.com/d/quotes.csv?s=%s&f=sl1t1v&e=.csv" 
symbols = ('GGP', 'JPM', 'AIG', 'AMZN','GGP', 'JPM', 'AIG', 'AMZN') 
#symbols = ('GGP') 

def fetch_quote(symbols): 
    url = URL % '+'.join(symbols) 
    fp = urllib.urlopen(url) 
    try: 
     data = fp.read() 
    finally: 
     fp.close() 
    return data 

def main(): 
    data_fp = fetch_quote(symbols) 
# print data_fp 
if __name__ =='__main__': 
    main() 
+0

Y at-il même tout ce que vous voulez faire en parallèle? Votre code fait simplement une seule requête. –

+0

Non, en ce moment, j'apprends Python en essayant de garder tout simple. merci – Merlin

+0

J'ai vu la méthode de processus, quelqu'un peut-il me montrer la méthode de filetage. Merci, merci – Merlin

Répondre

1

Vous avez un processus à la demande, plusieurs informations à la fois. Essayons de chercher ces informations, un par un .. Votre code sera:

def fetch_quote(symbols): 
    url = URL % '+'.join(symbols) 
    fp = urllib.urlopen(url) 
    try: 
     data = fp.read() 
    finally: 
     fp.close() 
    return data 

def main(): 
    for symbol in symbols: 
     data_fp = fetch_quote((symbol,)) 
     print data_fp 

if __name__ == "__main__": 
    main() 

donc appel principal(), un par un chaque URL pour obtenir les données. Faisons multiprocessus avec une piscine:

import urllib 
from multiprocessing import Pool 

URL = "http://download.finance.yahoo.com/d/quotes.csv?s=%s&f=sl1t1v&e=.csv" 
symbols = ('GGP', 'JPM', 'AIG', 'AMZN','GGP', 'JPM', 'AIG', 'AMZN') 

def fetch_quote(symbols): 
    url = URL % '+'.join(symbols) 
    fp = urllib.urlopen(url) 
    try: 
     data = fp.read() 
    finally: 
     fp.close() 
    return data 

def main(): 
    for symbol in symbols: 
     data_fp = fetch_quote((symbol,)) 
     print data_fp 

if __name__ =='__main__': 
    pool = Pool(processes=5) 
    for symbol in symbols: 
     result = pool.apply_async(fetch_quote, [(symbol,)]) 
     print result.get(timeout=1) 

Dans la principale suite à un nouveau processus est créé pour chaque demande urls symboles.

Note: sur python, puisque le GIL est présent, le multithreading doit être considéré comme une mauvaise solution.

Pour la documentation voir: Multiprocessing in python

+0

GIL n'est pas un problème ici parce que cette tâche est définitivement liée à IO. –

+0

merci, en essayant de comprendre le code, pas seulement le copier. – Merlin

+0

Je reçois beaucoup d'erreurs lors de l'exécution de longues listes de symboles. – Merlin

0

En fait, il est possible de le faire sans. Vous pouvez le faire dans un thread en utilisant des appels asynchrones, comme par exemple twisted.web.client.getPage de Twisted Web.

+0

@vartec pas besoin d'aller pour des paquets supplémentaires de tiers. Python2.6 + a déjà de très bons paquets intégrés pour ce genre de choses. –

+2

Euh oh, quelqu'un a mentionné Twisted, cela signifie que toutes les autres réponses vont être downvoted. http://stackoverflow.com/questions/3490173/how-can-i-speed-up-fetching-pages-with-urllib2-in-python/3490191#3490191 –

+0

@movieyoda: bien, pour des raisons évidentes (GAE, Jython) J'aime rester compatible avec 2.5. Quoi qu'il en soit, peut-être que je manque quelque chose, quel support pour les appels Web asynchrones a été introduit Python 2.6? – vartec

-1

Comme vous le savez, le multi-threading en Python n'est pas réellement multi-threading à cause de GIL. Essentiellement, c'est un seul thread qui s'exécute à un moment donné. Donc, dans votre programme si vous voulez que plusieurs URL soient récupérées à un moment donné, le multi-threading n'est peut-être pas la solution. Aussi après l'analyse, vous stockez les données dans un seul fichier ou un db persistant? La décision ici pourrait affecter votre performance.

Les processus multiples sont plus efficaces de cette façon, mais ont le temps & de mémoire de processus supplémentaires spawn. J'ai exploré ces deux options récemment dans Python. Voici l'URL (avec le code) -

python -> multiprocessing module

+2

Le code IO est exécuté sans acquérir le GIL. Pour les cartes liées à IO, le «threading» fonctionne bien. –

+0

Pouvez-vous donner un exemple de ci-dessus avec le filetage? – Merlin

+0

tout ce que je voulais dire, c'est qu'en considérant le multi-threading en Python, il faut garder à l'esprit le GIL. Après avoir obtenu les données d'URL, on peut vouloir l'analyser (créer DOM-> CPU Intensive) ou directement le vider dans un fichier (opération E/S). Dans ce dernier cas, l'effet de GIL serait minimisé, mais dans l'ancien GIL a joué un rôle important dans l'efficacité du programme. Donno pourquoi les gens le prennent tellement offensant qu'ils doivent downvote le poste ... –

1

Alors, voici un exemple très simple. Il itére sur les symboles en passant un à la fois à fetch_quote.

import urllib 
import multiprocessing 

URL = "http://download.finance.yahoo.com/d/quotes.csv?s=%s&f=sl1t1v&e=.csv" 
symbols = ('GGP', 'JPM', 'AIG', 'AMZN','GGP', 'JPM', 'AIG', 'AMZN') 
#symbols = ('GGP') 

def fetch_quote(symbol): 
    url = URL % '+'.join(symbol) 
    fp = urllib.urlopen(url) 
    try: 
     data = fp.read() 
    finally: 
     fp.close() 
    return data 


def main(): 

    PROCESSES = 4 
    print 'Creating pool with %d processes\n' % PROCESSES 
    pool = multiprocessing.Pool(PROCESSES) 
    print 'pool = %s' % pool 
    print 

    results = [pool.apply_async(fetch_quote, sym) for sym in symbols] 

    print 'Ordered results using pool.apply_async():' 
    for r in results: 
     print '\t', r.get() 

    pool.close() 
    pool.join() 

if __name__ =='__main__': 
    main() 
+0

Il peut y avoir des problèmes si les pages récupérées sont assez volumineuses. 'multiprocessing' utilise des mécanismes de communication inter-processus pour échanger des informations entre processus. –

+0

Vrai, ce qui précède était à titre d'illustration seulement. YMMV, mais je voulais montrer à quel point il était simple de prendre son code et de le rendre multiprocesseur. Je – mluebke

+0

eu cette erreur: Création piscine avec 4 processus piscine = résultats en utilisant pool.apply_async commandés(): \t retraçage (appel le plus récent) dernier: Fichier « C : \ py \ Raw \ Yh_Mp.py ", ligne 36, dans principal() Fichier" C: \ py \ Raw \ Yh_Mp.py ", ligne 30, dans principal imprimer '\ t', r.get() Fichier "C: \ Python26 \ lib \ multiprocessing \ pool.py", ligne 422, dans get raise self._value TypeError: fetch_quote() prend exactement 1 argument (3 donnés) – Merlin