Skip to main content
 首页 » 编程设计

python之如何使用 map 函数附加到列表

2025年04月02日34cmt

我正在尝试使用映射将 ping_all 函数映射到主机列表。 我遇到的问题是在 ping_all 函数中,我试图将所有失败的主机附加到列表中。通常我会调用 ping_all 函数,将空列表作为参数传递并返回修改后的列表,但由于我在这里使用 map,我不确定如何实现它?

import os 
import argparse 
from subprocess import check_output 
from multiprocessing import Pool 
 
 
parser = argparse.ArgumentParser(description='test') 
 
args = parser.parse_args() 
 
dead_hosts = [] 
 
 
def gather_hosts(): 
    """ Returns all environments from opsnode and puts them in a dict """ 
    host_list = [] 
    url = 'http://test.com/hosts.json' 
    opsnode = requests.get(url) 
    content = json.loads(opsnode.text) 
    for server in content["host"]: 
        if server.startswith("ip-10-12") and server.endswith(".va.test.com"): 
            host_list.append(str(server)) 
    return host_list 
 
 
def try_ping(hostnames): 
    try: 
        hoststatus = check_output(["ping", "-c 1", hostnames]) 
        print "Success:", hostnames 
    except: 
        print "\033[1;31mPing Failed:\033[1;m", hostnames 
        global dead_hosts 
        dead_hosts.append(hostnames) 
 
def show_dead_hosts(dead_hosts): 
    print '\033[1;31m******************* Following Hosts are Unreachable ******************* \n\n\033[1;m' 
    for i in dead_hosts: 
        print '\033[1;31m{0} \033[1;m'.format(i) 
 
if __name__ == '__main__': 
    hostnames = gather_hosts() 
    pool = Pool(processes=30)              # process per core 
    pool.map(try_ping, hostnames, dead_hosts) 
    show_dead_hosts(dead_hosts) 

我尝试将 dead_hosts 作为 map 中的第二个参数传递,但在运行此脚本后,dead_hosts 仍然是一个空列表,主机似乎没有附加到列表中。

我做错了什么?

请您参考如下方法:

您的代码有几个问题:

  1. Pool.map 的第三个参数是 chunksize,因此传递 dead_hosts(列表)肯定是不正确的。
  2. 使用多处理Pool 时无法访问全局变量,因为池中的任务在不同的进程中运行。参见 Python multiprocessing global variable updates not returned to parent 了解更多详情。
  3. 与上一点相关,Pool.map 应该返回一个结果列表(因为全局副作用大部分是不可见的)。现在您只是调用它并丢弃结果。
  4. 您的格式代码在我的终端中没有正确清除,所以一切都变成了粗体+红色...

这是我更新和测试过的一个版本——我认为它可以满足您的要求:

import os 
import argparse 
from subprocess import check_output 
from multiprocessing import Pool 
 
 
parser = argparse.ArgumentParser(description='test') 
 
args = parser.parse_args() 
 
def gather_hosts(): 
    """ Returns all environments from opsnode and puts them in a dict """ 
    host_list = [] 
    url = 'http://test.com/hosts.json' 
    opsnode = requests.get(url) 
    content = json.loads(opsnode.text) 
    for server in content["host"]: 
        if server.startswith("ip-10-12") and server.endswith(".va.test.com"): 
            host_list.append(str(server)) 
    return host_list 
 
 
def try_ping(host): 
    try: 
        hoststatus = check_output(["ping", "-c 1", "-t 1", host]) 
        print "Success:", host 
        return None 
    except: 
        print "\033[1;31mPing Failed:\033[0m", host 
        return host 
 
def show_dead_hosts(dead_hosts): 
    print '\033[1;31m******************* Following Hosts are Unreachable ******************* \n\n\033[0m' 
    for x in dead_hosts: 
        print '\033[1;31m{0} \033[0m'.format(x) 
 
def main(): 
    hostnames = gather_hosts() 
    pool = Pool(processes=30)              # process per core 
    identity = lambda x: x 
    dead_hosts = filter(identity, pool.map(try_ping, hostnames)) 
    show_dead_hosts(dead_hosts) 
 
if __name__ == '__main__': 
    main() 

我所做的主要更改是 try_ping 要么在成功时返回 None,要么在失败时返回 host 的名称。 ping 由您的任务池并行完成,结果聚合到一个新列表中。我在列表上运行一个 filter 以去除所有 None 值(None 在 Python 中是“falsey”),只留下未通过 ping 测试的主机名。

您可能希望摆脱 try_ping 中的 print 语句。我假设您只有那些用于调试的。

如果您需要更多的异步性,您还可以考虑使用 imap 和 ifilter。