concurrent.futures.ProcessPoolExecutor() map 无法读取全局变量
concurrent.futures.ProcessPoolExecutor() map can't read global variable
下面是使用 netmiko 进行网络自动化的简单代码:
所以首先我有:
- 函数cisco_command 用于从输入文件读取命令
- 函数cisco_host从输入文件中读取主机信息
- 用于启动与设备的连接的功能open_connection
- 多处理函数run_program
- 函数main为主程序
所以我的代码有问题,你可以在 open_connection func 上看到我们有全局变量 commands_info 但是如果我们 运行 这个程序通过多处理(run_program func) open_connection func.
无法读取全局变量
import time
import os
import concurrent.futures
from netmiko import ConnectHandler
from functools import partial
full_path = os.path.dirname(__file__)
host_file = os.path.join(full_path, "lab-router.txt")
command_file = os.path.join(full_path, "cisco-log.txt")
starting_time = ""
command_info = []
def cisco_command():
global command_info
command_info = []
with open(command_file, 'r') as commands:
for line in commands:
com = line.strip()
command_info.append(com)
return command_info
def cisco_host():
global starting_time
hosts_info = []
with open(host_file, 'r') as devices:
for line in devices:
deviceip = line.strip()
host = {
'device_type': 'cisco_ios',
'ip': deviceip,
'username': 'dodo',
'password': 'dodo',
'secret': 'dodo'
}
hosts_info.append(host)
starting_time = time.perf_counter()
return hosts_info
def open_connection(host):
global command_info
sendcommand = ""
try:
connection = ConnectHandler(**host)
print('Connection Established to Host:', host['ip'])
connection.enable()
for i in command_info:
sendcommand += "\n"
sendcommand += "==== {} ====".format(i)
sendcommand += "\n"
sendcommand += connection.send_command(i)
sendcommand += "\n"
# return sendcommand
with open("{}/{}_log.txt".format(full_path, host['ip']), 'w') as nf:
nf.write(sendcommand)
except:
print('Connection Failed to host', host['ip'])
def run_program(hosts_info):
with concurrent.futures.ProcessPoolExecutor() as executor:
results = executor.map(open_connection, hosts_info)
for result in results:
pass
finish = time.perf_counter()
print('Time Elapsed:', finish - starting_time)
def main():
commads = cisco_command()
hosts_info = cisco_host()
run_program(hosts_info)
if __name__ == '__main__':
main()
我不知道我错了什么
您写道:
if we run this program via multiprocessing (run_program func) the
global variable can't read by open_connection func.
这个说法其实是不正确的。你的全局变量 command_info
确实被函数 open_connection
读取了。这不是问题。
我看到您遇到的问题是您正在尝试使用命令 global
来更新每个 cpu 核心 command_info
中处理的更改 运行 将 open_connection
函数添加到主核心中的全局 command_info
中。这行不通。假设您同时有 4 cpus 运行,并且每个 cpu 都试图同时修改同一个全局术语。如果 Python 允许它不允许的东西,那将是一场噩梦。
实际上,Python 允许您将 command_info
传递到每个 CPU 核心(w/o 使用全局),您可以想到 command_info
现在是该计算核心独有的全局变量。要将每个唯一核心的更新 command_info
传递回 运行 concurrent.futures.ProcessPoolExecutor()
主核心,您必须在函数末尾 return command_info
open_connection(host)
(以及您的 sendcommand
)。然后在主核心中,您可以将其作为results
的result
中的术语之一进行访问。此后,您可以更新主核心中的全局 command_info
变量。
希望这个解释能帮助您理解您的问题。 :)
下面是使用 netmiko 进行网络自动化的简单代码: 所以首先我有:
- 函数cisco_command 用于从输入文件读取命令
- 函数cisco_host从输入文件中读取主机信息
- 用于启动与设备的连接的功能open_connection
- 多处理函数run_program
- 函数main为主程序
所以我的代码有问题,你可以在 open_connection func 上看到我们有全局变量 commands_info 但是如果我们 运行 这个程序通过多处理(run_program func) open_connection func.
无法读取全局变量import time
import os
import concurrent.futures
from netmiko import ConnectHandler
from functools import partial
full_path = os.path.dirname(__file__)
host_file = os.path.join(full_path, "lab-router.txt")
command_file = os.path.join(full_path, "cisco-log.txt")
starting_time = ""
command_info = []
def cisco_command():
global command_info
command_info = []
with open(command_file, 'r') as commands:
for line in commands:
com = line.strip()
command_info.append(com)
return command_info
def cisco_host():
global starting_time
hosts_info = []
with open(host_file, 'r') as devices:
for line in devices:
deviceip = line.strip()
host = {
'device_type': 'cisco_ios',
'ip': deviceip,
'username': 'dodo',
'password': 'dodo',
'secret': 'dodo'
}
hosts_info.append(host)
starting_time = time.perf_counter()
return hosts_info
def open_connection(host):
global command_info
sendcommand = ""
try:
connection = ConnectHandler(**host)
print('Connection Established to Host:', host['ip'])
connection.enable()
for i in command_info:
sendcommand += "\n"
sendcommand += "==== {} ====".format(i)
sendcommand += "\n"
sendcommand += connection.send_command(i)
sendcommand += "\n"
# return sendcommand
with open("{}/{}_log.txt".format(full_path, host['ip']), 'w') as nf:
nf.write(sendcommand)
except:
print('Connection Failed to host', host['ip'])
def run_program(hosts_info):
with concurrent.futures.ProcessPoolExecutor() as executor:
results = executor.map(open_connection, hosts_info)
for result in results:
pass
finish = time.perf_counter()
print('Time Elapsed:', finish - starting_time)
def main():
commads = cisco_command()
hosts_info = cisco_host()
run_program(hosts_info)
if __name__ == '__main__':
main()
我不知道我错了什么
您写道:
if we run this program via multiprocessing (run_program func) the global variable can't read by open_connection func.
这个说法其实是不正确的。你的全局变量 command_info
确实被函数 open_connection
读取了。这不是问题。
我看到您遇到的问题是您正在尝试使用命令 global
来更新每个 cpu 核心 command_info
中处理的更改 运行 将 open_connection
函数添加到主核心中的全局 command_info
中。这行不通。假设您同时有 4 cpus 运行,并且每个 cpu 都试图同时修改同一个全局术语。如果 Python 允许它不允许的东西,那将是一场噩梦。
实际上,Python 允许您将 command_info
传递到每个 CPU 核心(w/o 使用全局),您可以想到 command_info
现在是该计算核心独有的全局变量。要将每个唯一核心的更新 command_info
传递回 运行 concurrent.futures.ProcessPoolExecutor()
主核心,您必须在函数末尾 return command_info
open_connection(host)
(以及您的 sendcommand
)。然后在主核心中,您可以将其作为results
的result
中的术语之一进行访问。此后,您可以更新主核心中的全局 command_info
变量。
希望这个解释能帮助您理解您的问题。 :)