URL: https://linuxfr.org/forums/programmation-python/posts/multiprocessing Title: Multiprocessing Authors: Marotte ⛧ Date: 2016年12月23日T18:09:04+01:00 License: CC By-SA Tags: multiprocessing Score: 4 Bonjour, Afin de me former à l’utilisation de la bibliothèque _multiprocessing_ de Python3 j’écris un peu de code, pour mettre en pratique... Il y a des concepts que je ne comprends pas bien, d’où ce post. Pour mon exemple j’ai imaginé le problème suivant : une crèche, qui possède des nourrissons et des dortoirs, doit faire faire la sieste à tous les nourrissons. La sieste de l’ensemble des nourrissons d’un dortoir est terminée lorsque le dernier des nourrissons a fini sa sieste, les nourrissons dormant un temps aléatoire. Dans le code suivant, je fais dormir deux fois l’ensemble des nourrissons. Une première fois en utilisant un seul dortoir, donc un seul pool de process, j’utilise la fonction _map()_ du pool. Le temps nécessaire pour faire dormir tous les nourrissons c’est l’addition du temps de sieste de chaque chambrée, vu qu’elles occupe le dortoir l’une après l’autre. C’est le fonctionnement synchrone. Je comprends ce que fait le code, je n’ai pas d’interrogation dans ce cas. Pour faire dormir à nouveau l’ensemble des nourrissons j’emploie maintenant un ensemble de N dortoirs (N = nombre de nourrissons / taille d’un dortoir + 1) et la fonction _map_async()_, et c’est là que je commence à ne plus trop comprendre ce que je suis en train de faire... ```python #!/usr/bin/env python3 """Make all the toddlers in the nursery have their nap.""" from multiprocessing import Pool from random import randint, sample from time import sleep, time import string """What a toddler do when he’s having his nap.""" def nap(toddler): time = randint(0,5) print(toddler+' Zzz...', end=' ', flush=True) sleep(time) return(toddler, time) """Populate the nursery with toddlers.""" nurserySize = 24 dormitorySize = 5 toddlers = [] while (len(toddlers) < nurserySize): # Every toddler has a name toddlers.append(''.join(sample(string.ascii_lowercase,randint(3,7))).capitalize()) """For all toddlers, make them nap grouped in available dormitories. The nap is finished for all the toddlers in a dormitory when the last one wakes up.""" """1. Only one dormitory, the nap must be finished, then the next group of toddlers can have their own.""" start = time() barrack = Pool(dormitorySize) sleepAmount = 0 # Total sleep amount for all toddlers of the nursery print(str(len(toddlers))+' toddlers going to sleep, '+str(dormitorySize)+' by '+str(dormitorySize)+' in one dormitory.') for i in range(0, nurserySize, dormitorySize): dormitory = barrack.map(nap, toddlers[i:i+dormitorySize]) #~ print("\n", dormitory) for toddler in dormitory: sleepAmount += toddler[1] _time = time() - start _ratio = sleepAmount/_time print("\n\n",' → Tooks '+str(_time)+' seconds for '+str(sleepAmount)+' of sleep. ('+str(_ratio)+')',"\n") """2. Now the same again, but we have as many dormitories as needed, to nap all the toddlers at once.""" start = time() barracks = [Pool(dormitorySize)] * (int(nurserySize/dormitorySize) + 1) sleepAmount = 0 dormitories = [] j = 0 # The callback function will be called when the pool has finished. def fillDormitory(toddlers): dormitories.append(toddlers) print(str(len(toddlers))+' toddlers going to sleep '+str(dormitorySize)+' by '+str(dormitorySize)+' in '+str(len(barracks))+' dormitories.') for i in range(0, nurserySize, dormitorySize): barracks[j].map_async(nap, toddlers[i:i+dormitorySize], callback=fillDormitory) j += 1 for b in barracks: b.close() b.join() # Count total sleep amount. for dormitory in dormitories: for toddler in dormitory: sleepAmount += toddler[1] print(dormitories) _time = time() - start _ratio = sleepAmount/_time print("\n",' → Tooks '+str(_time)+' seconds for '+str(sleepAmount)+' of sleep. ('+str(_ratio)+')',"\n") ``` Je m’attendais avec la deuxième méthode que ça corresponde au fonctionnement suivant : je répartie les nourrissons dans tous les dortoirs disponibles, donc ils commencent tous leur sieste en même temps, c’est la première boucle. Ensuite, deuxième boucle, sur chaque dortoir (avec le _close()_ et le _join()_) je vais « voir si les nourrissons ont fini leur sieste ». Je pensais qu’ainsi, le temps total correspondrait au temps de sieste du dortoir qui a le plus élevé. Autrement dit, en prenant les dortoirs dans l’ordre dans la seconde boucle, si je dois attendre la fin de la sieste, j’aurais probablement pas à attendre beaucoup pour les suivants, qui auront commencé la sieste en même temps que le premier dortoir. Mais bien sûr ce n’est pas ça qui se passe... Voilà ce que j’observe : la deuxième méthode va toujours plus vite que la première, **sauf dans le cas où tous les nourrissons dorment un temps identique**, là le temps est équivalent à la première méthode ! Pour obtenir ce que je souhaite, c’est à dire que le temps total d’exécution soit égal au temps d’exécution du plus « lent » des pools, j’ai le sentiment que je ne peux pas utiliser _map_async()_ et qu’il faut que je passe par _apply_async()_ et par l’utilisation d’objet Process() individuellement... Mais je sèche un peu... qu’en pensez-vous ?

AltStyle によって変換されたページ (->オリジナル) /