J'ai le code suivant où j'ai une liste de noms d'utilisateurs et j'essaie de vérifier si les utilisateurs sont dans un groupe d'utilisateurs Windows spécifique en utilisant Net User \domain | find somegroup
.
Le problème est que je lance cette commande pour environ 8 groupes d'utilisateurs par nom d'utilisateur, ce qui est lent. Je voudrais envoyer ces appels en utilisant des futures et même des threads séparés (si cela le rend plus rapide).
Je dois juste attendre à la fin avant de faire autre chose. Comment puis-je m'y prendre en Python?
for one_username in user_list:
response = requests.get(somecontent)
bs_parsed = BeautifulSoup(response.content, 'html.parser')
find_all2 = bs_parsed.find("div", {"class": "QuickLinks"})
name = re.sub("\s\s+", ' ', find_all2.find("td", text="Name").find_next_sibling("td").text)
find_all = bs_parsed.find_all("div", {"class": "visible"})
all_perms = ""
d.setdefault(one_username + " (" + name + ")", [])
for value in find_all:
test = value.find("a", {"onmouseover": True})
if test is not None:
if "MyAppID" in test.text:
d[one_username + " (" + name + ")"].append(test.text)
for group in groups:
try:
d[one_username + " (" + name + ")"].append(check_output("Net User /domain " + one_username + "| find \"" + group + "\"", Shell=True, stderr=subprocess.STDOUT).strip().decode("utf-8"))
except Exception:
pass
(Cette réponse ignore actuellement le code HTML. L'analyse de votre code ne ... vous pouvez la mettre dans un pool de la même manière que cette approche met en attente les appels Net User
)}
Commençons par définir une fonction qui prend une Tuple
de (user, group)
et renvoie les informations souhaitées.
# a function that calls Net User to find info on a (user, group)
def get_group_info(usr_grp):
# unpack the arguments
usr, grp = usr_grp
try:
return (usr, grp,
check_output(
"Net User /domain " + usr + "| find \"" + grp + "\"",
Shell=True,
stderr=subprocess.STDOUT
).strip().decode("utf-8")))
except Exception:
return (usr, grp, None)
Maintenant, nous pouvons l’exécuter dans un pool de threads en utilisant multiprocessing.dummy.Pool
from multiprocessing.dummy import Pool
import itertools
# create a pool with four worker threads
pool = Pool(4)
# run get_group_info for every user, group
async_result = pool.map_async(get_group_info, itertools.product(user_list, groups))
# now do some other work we care about
...
# and then wait on our results
results = async_result.get()
La results
est une liste de (user, group, data)
tuples et peut être traitée à votre guise.
Remarque: Ce code est actuellement non testé en raison d'une différence de plate-forme
En python 3, une solution plus simple et plus pratique consiste à utiliser concurrent.futures
.
Le module
concurrent.futures
fournit une interface de haut niveau pour l'exécution des appelables de manière asynchrone. Référence...
import concurrent.futures
# Get a list containing all groups of a user
def get_groups(username):
# Do the request and check here
# And return the groups of current user with a list
return list()
with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor:
# Mark each future with its groups
future_to_groups = {executor.submit(get_groups, user): user
for user in user_list}
# Now it comes to the result of each user
for future in concurrent.futures.as_completed(future_to_groups):
user = future_to_groups[future]
try:
# Receive the returned result of current user
groups = future.result()
except Exception as exc:
print('%r generated an exception: %s' % (user, exc))
else:
# Here you do anything you need on `groups`
# Output or collect them
print('%r is in %d groups' % (user, len(groups)))
Notez que max_workers
signifie ici le nombre maximal de threads.
Voir ici d'où provient cet exemple.
MODIFIER:
Si vous devez faire chaque vérification dans un fil séparé:
import concurrent.futures
# Check if a `user` is in a `group`
def check(user, group):
# Do the check here
# And return True if user is in this group, False if not
return True
with concurrent.futures.ThreadPoolExecutor(max_workers=5) as executor:
# Mark each future with its user and group
future_to_checks = {executor.submit(check, user, group): (user, group)
for user in user_list for group in group_list}
# Now it comes to the result of each check
# The try-except-else clause is omitted here
for future in concurrent.futures.as_completed(future_to_checks):
user, group = future_to_checks[future]
in_group = future.result()
if in_group is True:
print('%r is in %r' % (user, group))
Inspiré par @donkopotamus, itertools.product
pourrait être utilisé ici pour générer toutes les cibles.
Et si vous n'avez pas besoin de gérer les exceptions, ce serait beaucoup plus simple:
import concurrent.futures
from itertools import product
from collections import defaultdict
def check(target):
user, group = target
return True
with concurrent.futures.ThreadPoolExecutor() as executor:
results = defaultdict(list)
targets = list(product(user_list, group_list))
for (user, group), in_group in Zip(targets, executor.map(check, targets)):
if in_group is True:
results[user].append(group)
print(results)
Il semble que problème du consommateur producteur .
Le fil principal devrait générer les tâches
class Task:
def Task(self,user,group)
self.user = user
self.group = group
def run(self):
pass # call command with self.user and self.group and process results
twp = TaskWorkerPool(4)
for group in groups:
twp.add( Task(user,group) )
twp.wait()