Question

J'écris un petit robot qui devrait récupérer une URL plusieurs fois, je veux que tous les threads s'exécutent en même temps (simultanément).

J'ai écrit un petit bout de code qui devrait faire ça.

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)

D'après les journaux Apache, il ne semble pas que les threads fonctionnent simultanément, il y a un petit écart entre les requêtes, c'est presque indétectable mais je peux voir que les threads ne sont pas vraiment parallèles.

J'ai lu sur GIL, y a-t-il un moyen de le contourner sans appeler un code C \ C ++? Je ne comprends pas vraiment comment le threading est possible avec GIL?python interprète essentiellement le fil suivant dès qu'il se termine par le précédent?

Merci.

Était-ce utile?

La solution

Comme vous le faites remarquer, le GIL empêche souvent les threads Python de s'exécuter en parallèle.

Cependant, ce n'est pas toujours le cas.Une exception est le code lié aux E / S.Lorsqu'un thread attend la fin d'une demande d'E / S, il aurait généralement libéré le GIL avant d'entrer dans l'attente.Cela signifie que d'autres threads peuvent progresser entre-temps.

En général, cependant, multiprocessing est le pari le plus sûr lorsqu'un vrai parallélisme est requis.

Autres conseils

J'ai lu sur GIL, y a-t-il un moyen de le contourner sans appeler un code C \ C ++?

Pas vraiment.Les fonctions appelées via ctypes libéreront le GIL pendant la durée de ces appels.Les fonctions qui exécutent le blocage des E / S le libéreront également.Il existe d'autres situations similaires, mais elles impliquent toujours du code en dehors de la boucle principale de l'interpréteur Python.Vous ne pouvez pas abandonner le GIL dans votre code Python.

Vous pouvez utiliser une approche comme celle-ci pour créer tous les threads, leur faire attendre un objet de condition, puis leur demander de commencer à récupérer l'url " simultanément ":

#!/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()

Cela vous rapprocherait un peu plus de la réalisation de toutes les récupérations en même temps, MAIS :

  • Les paquets réseau quittant votre ordinateur passeront le long du câble Ethernet dans l'ordre, pas en même temps,
  • Même si vous avez plus de 16 cœurs sur votre machine, certains routeurs, ponts, modems ou autres équipements entre votre machine et l'hôte Web auront probablement moins de cœurs et pourront sérialiser vos demandes,
  • Le serveur Web à partir duquel vous récupérez des informations utilisera un appel accept() pour répondre à votre demande. Pour un comportement correct, cela est implémenté à l'aide d'un verrou global de serveur pour garantir qu'un seul processus / thread serveur répond à votre requête. Même si certaines de vos requêtes arrivent sur le serveur simultanément , cela entraînera une sérialisation.

Vous obtiendrez probablement que vos requêtes se se chevauchent dans une plus grande mesure (c'est-à-dire que d'autres commencent avant la fin), mais vous n'obtiendrez jamais toutes vos requêtes démarrées simultanément < / em> sur le serveur.

Vous pouvez également regarder des choses comme l'avenir de pypy où nous aurons une mémoire de transition logicielle (éliminant ainsi le GIL). Tout cela n'est que de la recherche et des moqueries intellectuelles pour le moment, mais cela pourrait devenir quelque chose de grand.

Si vous exécutez votre code avec Jython ou IronPython (et peut-être PyPy dans le futur), il fonctionnera en parallèle

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top