如何进行未来的调用并等待 Python 完成?

新手上路,请多包涵

我有以下代码,其中有一个用户名列表,我尝试使用 net user \domain | find somegroup 检查用户是否在特定的 Windows 用户组中。

问题是我为每个用户名大约 8 个用户组运行该命令而且速度很慢。我想使用 futures 甚至单独的线程发送这些调用(如果它更快)。

在我做任何其他事情之前,我只需要等到最后。我该如何在 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

原文由 orange 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 454
2 个回答

(这个答案目前忽略了 HTML 解析你的代码……你可以将它排队到一个池中,就像这种方法排队 net user 调用一样)

首先,让我们定义一个函数,它接受 tuple(user, group) 并返回所需的信息。

 # 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)

现在,我们可以使用 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()

results(user, group, data) 元组的列表,可以根据需要进行处理。

注意: 由于平台差异,此代码目前未经测试

原文由 donkopotamus 发布,翻译遵循 CC BY-SA 4.0 许可协议

在python 3中,更简单方便的解决方案是使用 concurrent.futures

concurrent.futures 模块为异步执行可调用对象提供了一个高级接口。 参考…

 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)))

请注意,这里的 max_workers 表示最大线程数。

请参阅 此处 示例的来源。

编辑:

如果您需要在单独的线程中进行每次检查:

 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))

受@donkopotamus 的启发, itertools.product 可以在此处用于生成所有目标。

如果你不需要处理异常,那就简单多了:

 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)

原文由 Roll 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题