【问题标题】:Python, ssh and multithreading : threads can only be started oncePython、ssh 和多线程:线程只能启动一次
【发布时间】:2019-02-28 16:26:38
【问题描述】:

我正在使用 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")

谢谢

【问题讨论】:

  • 您将同一个线程多次附加到同一个列表中,因此在您启动线程的 for 循环中出现此错误:线程只能启动一次。对于第二个错误,您可能正在尝试加入未启动的线程。
  • 有一天,当你有空的时候,你应该坐下来了解一下Test Driven Development。我知道围绕这个主题有很多炒作,也有很多误解。但是如果你做对了,那么你将很少有一天不得不告诉别人,“不幸的是,除非你 [可以复制我的环境]”,否则代码将无法执行,因为大多数您的代码将在您的测试工具中可执行,您将能够在大多数地方执行。
  • 感谢您的见解。由于我的公司不想花任何时间或金钱,我正在为这个“流氓”工作,所以我的时间是有限的。我想我通过在 for 循环的开头添加 threads = [] 来解决我的问题,并且仍然将正在运行的线程存储在 dict 中:allthreads[i] = threads
  • 是的,这是一个解决方案。但也要检查我的答案

标签: multithreading python-2.7 ssh


【解决方案1】:

注意理解我的语言:

范围循环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()

threads 列表包含多个线程(即同一个线程),这是您需要的,但不是正确的方式。

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(所以你多次启动同一个线程)。

所以,为了解决这个问题,你可以将开始和加入列表保留在你的代码位置,并在开始和加入后添加线程删除,或者你可以将开始和加入循环移出范围循环。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-06-21
    • 1970-01-01
    • 1970-01-01
    • 2020-12-13
    • 2015-03-24
    • 1970-01-01
    • 2021-11-29
    相关资源
    最近更新 更多