Python,ssh和多线程:线程只能启动一次

时间:2019-02-27 21:48:29

标签: multithreading python-2.7 ssh

我正在使用Python和Netmiko通过ssh连接在我的网络基础结构中进行爬网。不幸的是,除非您拥有自己的类似网络基础结构,否则代码将无法执行。

我的问题更多是关于python中的多线程理论。

这是我想要实现的算法:

连接到我的核心交换机。 收集邻居信息。 断开连接

在列表中放置邻居。 浏览列表: 连接到每个邻居 收集邻居信息。 断开 将新邻居放在同一列表中。

这是主要的问题循环:

#ssh to all equipements in neighbors detecteid, gather info+ update neighbors list. Multithread to be much faster
    #cannot be more than 6 waves of uplink
    for i in range(6):
        #browse switch name in the list
        for a_device in switch_list[3::3]:
            #if the neighbor was not already analyzed
            if not switch_list[switch_list.index(a_device)+2]:
                    print('connection to...' + a_device)
                    #multithread all neighbors to be analyzed and update list
                    threads.append(threading.Thread(target=ssh_and_gather, args=(a_device,location,switch_list)))

        for x in threads:
            x.start()

        for x in threads:
            x.join()

它失败并显示以下错误:

Traceback (most recent call last):
  File "ansible_switch_discover.py", line 130, in <module>
    main()
   File "ansible_switch_discover.py", line 114, in main
    x.start()
  File "/usr/lib64/python2.7/threading.py", line 741, in start
    raise RuntimeError("threads can only be started once")

我该如何修复我的代码,使其继续向多线程添加线程(到新发现的邻居的ssh连接)?

我只尝试过一次start(),但是错误是:

Traceback (most recent call last):
  File "ansible_switch_discover.py", line 132, in <module>
    main()
  File "ansible_switch_discover.py", line 119, in main
    x.join()
  File "/usr/lib64/python2.7/threading.py", line 940, in join
    raise RuntimeError("cannot join thread before it is started")

谢谢

1 个答案:

答案 0 :(得分:0)

请注意了解我的语言:

范围循环for i in range(6):

启动循环

for x in threads:
            x.start()

加入循环

for x in threads:
            x.join()

问题是您试图多次启动同一线程:

for i in range(6):
    for a_device in switch_list[3::3]:
        if not switch_list[switch_list.index(a_device)+2]:
                print('connection to...' + a_device)
                threads.append(threading.Thread(target=ssh_and_gather, args=(a_device,location,switch_list)))

    for x in threads:
        x.start()

    for x in threads:
        x.join()

列表线程包含多个线程(属于同一线程),这是您所需要的,但不是正确的方法。

start和join循环的位置不正确,您可以解决将其放置在这样的情况(在range循环之外):

threads = list()
for i in range(6):
    for a_device in switch_list[3::3]:
        if not switch_list[switch_list.index(a_device)+2]:
                print('connection to...' + a_device)
                threads.append(threading.Thread(target=ssh_and_gather, args=(a_device,location,switch_list)))

for x in threads:
    x.start()

for x in threads:
    x.join()

现在在此代码中,首先创建所有线程,然后启动并加入它,因此不会出现任何错误,因为您不会多次启动同一线程。

执行此操作的另一种方法是保留代码,并在启动和加入循环之后清除线程列表,因此该线程仅启动一次。


尝试解释:

这是第一个范围循环之后的线程列表:

threads = [th1, th2, th3, th4, th5, th6]

现在所有这些线程都根据您的代码启动并加入了。 在第二个循环中,将更多线程附加到列表中:

threads = [th1, th2, th3, th4, th5, th6, th1, th2, th3, th4, th5, th6]

现在,您开始并再次连接线程,但是,您在列表的位置0开始th1,当您在列表的位置6到达th1时,它会引发错误,因为是相同的对象th1(因此您多次启动同一线程)。

因此,要解决该问题,可以将启动和联接列表保留在代码位置,并在启动和联接后添加线程删除,或者可以将范围和循环移出启动和联接循环。