2017-10-14 6 views
1

Pourquoi est-ce le code ci-dessous exécution lors de l'utilisation threads mais jeter une exception lorsque multiprocessing est utilisé?Pourquoi multiprocessing.pool.map déclenche un PicklingError (Encoding)?

from multiprocessing import Pool 
from multiprocessing.dummy import Pool as ThreadsPool 
import urllib2 

urls = [ 
    'http://www.python.org', 
    'http://www.python.org/about/', 
    'http://www.python.org/doc/', 
    'http://www.python.org/download/'] 

def use_threads(): 

    pool = ThreadsPool(4) 
    results = pool.map(urllib2.urlopen, urls) 
    pool.close() 
    pool.join() 

    print [len(x.read()) for x in results] 

def use_procs(): 

    p_pool = Pool(4) 
    p_results = p_pool.map(urllib2.urlopen, urls) 
    p_pool.close() 
    p_pool.join() 

    print 'using procs instead of threads' 
    print [len(x.read()) for x in p_results] 

if __name__ == '__main__': 
    use_procs() 

L'exception est

Traceback (most recent call last): 
    File "pools.py", line 39, in <module> 
    use_procs() 
    File "pools.py", line 31, in use_procs 
    p_results = p_pool.map(urllib2.urlopen, urls) 
    File "/usr/lib64/python2.7/multiprocessing/pool.py", line 250, in map 
    return self.map_async(func, iterable, chunksize).get() 
    File "/usr/lib64/python2.7/multiprocessing/pool.py", line 554, in get 
    raise self._value 
multiprocessing.pool.MaybeEncodingError: Error sending result: '[<addinfourl at 35286624 whose fp = <socket._fileobject object at 0x2198ad0>>]'. Reason: 'PicklingError("Can't pickle <type 'instancemethod'>: attribute lookup __builtin__.instancemethod failed",)' 

Je sais qu'il ya une différence entre la façon dont les processus et les fils communiquent entre eux. Pourquoi pickle échoue sur le contenu du site Web? Comment puis-je définir l'encodage pour résoudre ce problème?

+1

Cette erreur a soulevé parce que vous essayez de sérialisation objet socket, ce qui est impossible –

+0

avoir une idée quelle fonction dois-je passer à la carte pour obtenir la sortie désirée? (Lire l'exécution sur l'objet) – Vinny

Répondre

3

Le problème ISN 't une erreur d'encodage, c'est à cause d'une erreur de décapage puisque le résultat urllib2.urlopen() renvoie un objet non picklable (un _ssl._SSLSocket selon la raison légèrement différente montrée dans le message d'erreur que je reçois avec votre code). Pour contourner ce problème, vous pouvez limiter l'utilisation de l'objet renvoyé au sous-processus lui-même en lisant les données après avoir ouvert l'URL comme indiqué ci-dessous. Cela signifie probablement que beaucoup plus de données devront être transmises entre les processus.

# Added. 
def get_data(url): 

    soc = urllib2.urlopen(url) 
    return soc.read() 

def use_procs(): 

    p_pool = Pool(4) 
# p_results = p_pool.map(urllib2.urlopen, urls) 
    p_results = p_pool.map(get_data, urls) 
    p_pool.close() 
    p_pool.join() 

    print 'using procs instead of threads' 
# print [len(x.read()) for x in results] 
    print [len(x) for x in p_results] 

Sortie:

using procs instead of threads 
[49062, 41616, 40086, 101224] 
2

Comme je l'ai déjà mentionné - cette erreur est soulevée parce que vous avez essayé de passer l'objet socket entre les processus. Vous devez changer la logique de script dans quelque chose comme ceci:

from multiprocessing.pool import Pool 
from multiprocessing.pool import ThreadPool 
import urllib2 

urls = [ 
    'http://www.python.org', 
    'http://www.python.org/about/', 
    'http://www.python.org/doc/', 
    'http://www.python.org/download/' 
] 

def worker(url): 
    return urllib2.urlopen(url).read() # string returned 

def use_threads(): 

    pool = ThreadPool(4) 
    results = pool.map(worker, urls) 
    pool.close() 
    pool.join() 

    print([len(x) for x in results]) 

def use_procs(): 

    p_pool = Pool(4) 
    p_results = p_pool.map(worker, urls) 
    p_pool.close() 
    p_pool.join() 

    print('using procs instead of threads') 
    print([len(x) for x in p_results]) 

if __name__ == '__main__': 
    use_procs() 

A propos: vous pourriez faire l'usine de la piscine et de choisir la piscine de ce lieu de dupliquer le code dans use_threads et use_procs:

from multiprocessing.pool import Pool 
from multiprocessing.pool import ThreadPool 
import urllib2 

urls = [ 
    'http://www.python.org', 
    'http://www.python.org/about/', 
    'http://www.python.org/doc/', 
    'http://www.python.org/download/' 
] 


def worker(url): 
    return urllib2.urlopen(url).read() 


def pool_factory(key, n): 
    if key == 'proc': 
     print('using procs instead of threads') 
     return Pool(n) 
    else: 
     return ThreadPool(n) 


def main(): 

    pool = pool_factory('proc', 4) # change `proc` to anything for using ThreadPool 
    results = pool.map(worker, urls) 
    pool.close() 
    pool.join() 
    print([len(x) for x in results]) 


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

Merci pour l'entrée. Vous aviez raison à propos de la chaîne retournée; Je n'ai pas créé de méthode d'usine car ce code est uniquement destiné à la pratique, ne doit pas être utilisé dans d'autres codes :-) – Vinny