concurrent.futures.ProcessPoolExecutor() 映射无法读取全局变量

问题描述

我有使用 netmiko 进行网络自动化的简单代码: 所以首先我有

  1. 函数 cisco_command 从输入文件读取命令
  2. 函数 cisco_host 从输入文件中读取主机信息
  3. 函数 open_connection 用于启动与设备的连接
  4. 用于多处理的函数 run_program
  5. function 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()

我不知道我错了什么

解决方法

你写道:

如果我们通过多处理(run_program func)运行这个程序 open_connection func 无法读取全局变量。

这个说法其实是错误的。您的全局变量 command_info 确实由函数 open_connection 读取。这不是问题。

我看到您遇到的问题是您正在尝试使用命令 global 来更新 command_info 中由运行 open_connection 的每个 CPU 内核处理的更改函数到主内核中的全局 command_info。这行不通。想象一下,您有 4 个 cpu 同时运行,每个 cpu 都试图同时修改同一个全局术语。如果 Python 允许它不允许的东西,那将是一场噩梦。

实际上,Python 允许您将 command_info 传递到每个 CPU 内核(不使用全局),您现在可以将 command_info 视为该计算内核独有的全局变量。要将每个唯一内核的更新后的 command_info 传递回运行 concurrent.futures.ProcessPoolExecutor() 的主内核,您必须在函数 command_info 的末尾返回 open_connection(host)(以及你的sendcommand)。然后在主核心中,您可以将其作为 result of results 中的术语之一访问。此后,您可以更新主内核中的全局 command_info 变量。

希望此说明能帮助您了解您的问题。 :)