我正在尝试使用映射将 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 仍然是一个空列表,主机似乎没有附加到列表中。
我做错了什么?
最佳答案
您的代码有几个问题:
-
Pool.map
的第三个参数是chunksize
,因此传递dead_hosts
(列表)肯定是不正确的。 - 使用多处理
Pool
时无法访问全局变量,因为池中的任务在不同的进程中运行。参见 Python multiprocessing global variable updates not returned to parent 了解更多详情。 - 与上一点相关,
Pool.map
应该返回一个结果列表(因为全局副作用大部分是不可见的)。现在您只是调用它并丢弃结果。 - 您的格式代码在我的终端中没有正确清除,所以一切都变成了粗体+红色...
这是我更新和测试过的一个版本——我认为它可以满足您的要求:
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
。
关于python - 如何使用 map 函数附加到列表?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36510412/