如何使用map函数追加到列表?

时间:2016-04-08 22:36:44

标签: python dictionary

我正在尝试使用map,将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仍然是一个空列表,看起来主机没有附加到列表中。

我做错了什么?

2 个答案:

答案 0 :(得分:1)

您的代码存在以下问题:

  1. Pool.map的第三个参数是chunksize,因此传递dead_hosts(列表)肯定是不正确的。
  2. 使用多处理Pool时,您无法访问全局变量,因为池中的任务在不同的进程中运行。有关详细信息,请参阅 Python multiprocessing global variable updates not returned to parent
  3. 与上一点相关,Pool.map应该返回一个结果列表(因为全局副作用基本上是不可见的)。现在你只是打电话给它并扔掉了结果。
  4. 您的格式代码未在我的终端中正确清除,因此所有内容都变为粗体+红色......
  5. 这是我更新和测试过的版本 - 我认为它符合您的要求:

    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在" falsey"在Python中),只留下失败的主机名ping测试。

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

    如果您需要更多异步,也可以考虑使用imapifilter

答案 1 :(得分:0)

您的try_ping函数实际上没有返回任何内容。如果我是你,我不会在函数之外但在try_ping函数内部使用dead_hosts。然后你应该return该列表。

我不熟悉您正在使用的模块,因此我不知道pool.map是否可以使用列表。