我试图编写一个程序,将路由器输出中的一些数据与数据库中的数据进行比较。为了加快速度(有相当数量的设备)我希望它具有多线程。如果我只启动2个线程,我认为我应该有3个线程。主线程和两个工人。但由于某种原因,我最终得到5个线程,然后下降到3个线程,但从不低于3个线程(我假设两个线程的丢失来自两个工作线程完成)。我永远不会回到1个线程,所以我无限期地陷入困境。我在代码中遗漏了一些明显的东西吗?
主程序:
from orionsdk import SwisClient
from getpass import getpass
import xlsxwriter
import signal
import threading
import queue
import sys
import time
from colorama import Fore, Style, init
from device_solarwinds_comparison import compare
init() # init colorama
results = []
class SignalHandler:
"""
The object that will handle signals and stop the worker threads.
"""
#: The stop event that's shared by this handler and threads.
stopper = None
#: The pool of worker threads
workers = None
def __init__(self, stopper, workers):
self.stopper = stopper
self.workers = workers
def __call__(self, signum, frame):
# This will be called by the python signal module
print("Telling threads to exit.")
self.stopper.set()
print("Waiting for threads to finish up.")
for worker in self.workers:
worker.join()
sys.exit(0)
class AsyncComparison(threading.Thread):
# The queue of work
work_queue = None
# The event that tells the thread to stop
stopper = None
def __init__(self, work_queue, stopper):
super().__init__()
self.device_queue = work_queue
self.id = threading.Thread.getName(self)
self.lock = threading.Lock()
self.stopper = stopper
def run(self):
while not self.stopper.is_set():
try:
swis_result = self.device_queue.get_nowait()
except queue.Empty:
break
else:
print(Style.BRIGHT + Fore.BLUE + "[{0}]".format(self.id) + Style.RESET_ALL + " " + Fore.GREEN + swis_result['Caption'] + Style.RESET_ALL)
result = compare(swis_result)
with self.lock:
results.append(result)
self.device_queue.task_done()
def main():
# Set number of worker threads
num_workers = 2
# Create stopper event
stopper = threading.Event()
# Create a work queue
work_queue = queue.Queue()
sw_username = 'user'
sw_password = 'pass'
swis = SwisClient(hostname='host', username=sw_username, password=sw_password)
swis_results = swis.query("""SELECT TOP 2 N.Caption, N.CustomProperties.Site_Tier, N.CustomProperties.Bandwidth,
N.CustomProperties.Carrier, N.CustomProperties.CircuitID, N.CustomProperties.GOLDCAR,
N.CustomProperties.Tier1Broadband, N.CustomProperties.Tier1BroadbandSpeed, N.CustomProperties.Tier1BroadbandProvider
FROM Orion.Nodes N
WHERE N.Caption LIKE '%rt-0%'""")
swis_results = swis_results['results']
for result in swis_results:
work_queue.put(result)
# Create workers
workers = [AsyncComparison(work_queue, stopper) for i in range(num_workers)]
# Create our signal handler and pass it the stopper event and the workers
handler = SignalHandler(stopper, workers)
# Attach the SIGINT signal to our handler
signal.signal(signal.SIGINT, handler)
# Start the worker threads
for i, worker in enumerate(workers):
print(i)
worker.start()
# While threads are active we will sleep. Slight performance hit compared to blocking with .join
# but this will enable the main thread to catch interrupts so we can exit with ctrl+c
while threading.active_count() > 1:
print("{0}".format(threading.active_count()))
time.sleep(1)
# Create a workbook and add a worksheet.
workbook = xlsxwriter.Workbook('Circuit_Comparison.xlsx')
worksheet = workbook.add_worksheet()
# Add formats
bold = workbook.add_format({'bold': True})
red_bg = workbook.add_format({'bg_color': 'red'})
# Write some data headers.
worksheet.write('A1', 'Device', bold)
worksheet.write('B1', 'Device_CircuitID', bold)
worksheet.write('C1', 'Device_Bandwidth', bold)
worksheet.write('D1', 'Device_ServicePolicy', bold)
worksheet.write('E1', 'Device_GOLDCAR', bold)
worksheet.write('F1', 'Device_Carrier', bold)
worksheet.write('G1', 'Device_Tier1_BB_Provider', bold)
worksheet.write('H1', 'Device_Tier1_BB_Speed', bold)
worksheet.write('I1', 'Solarwinds_CircuitID', bold)
worksheet.write('J1', 'Solarwinds_Bandwidth', bold)
worksheet.write('K1', 'Solarwinds_GOLDCAR', bold)
worksheet.write('L1', 'Solarwinds_Carrier', bold)
worksheet.write('M1', 'Solarwinds_Tier1_BB_Provider', bold)
worksheet.write('N1', 'Solarwinds_Tier1_BB_Speed', bold)
# Start from the first cell below the headers.
row = 1
col = 0
print("Results: {0}".format(results))
for item in results:
print(item)
# Convert the date string into a datetime object.
worksheet.write_string(row, col, item[0])
if item[2] == item[3] or not item[3]: # If bandwidth equal to service_policy, or there's no service_policy
worksheet.write_string(row, col + 2, item[2])
worksheet.write_string(row, col + 3, item[3])
else:
worksheet.write_string(row, col + 2, item[2], red_bg)
worksheet.write_string(row, col + 3, item[3], red_bg)
# Convert SW bandwidth to lower case, split on x, take the first number, convert to float (because of decimals)
processed_sw_bandwidth = float(item[9].lower().split('x')[0])
# If bandwidth is less than 100 it's probably in mbps, convert to kbps
if processed_sw_bandwidth < 100:
processed_sw_bandwidth *= 1000
# If the Solarwinds bandwidth doesn't equal the device bandwidth
# (convert float to integer to get rid of decimal then to string for comparison)
if str(int(processed_sw_bandwidth)) != item[2]:
worksheet.write_string(row, col + 2, item[2], red_bg)
worksheet.write_string(row, col + 9, item[9], red_bg)
else:
worksheet.write_string(row, col + 9, item[9])
# If device goldcar not equal to Solarwinds goldcar
if str(item[4]) != str(item[10]):
worksheet.write_string(row, col + 4, item[4], red_bg)
worksheet.write_string(row, col + 10, str(item[10]), red_bg)
elif not str(item[4]) and str(item[10]) == 'None': # No device Goldcar and Solarwinds reports None for Goldcar
worksheet.write_string(row, col + 4, item[4])
worksheet.write_string(row, col + 10, str(item[10]))
else:
worksheet.write_string(row, col + 4, item[4])
worksheet.write_string(row, col + 10, str(item[10]))
# If we're missing a circuit ID somewhere
if not item[8] and item[1]:
worksheet.write_string(row, col + 1, item[1], red_bg)
worksheet.write_string(row, col + 8, '', red_bg)
elif item[8] and not item[1]:
worksheet.write_string(row, col + 1, '', red_bg)
worksheet.write_string(row, col + 8, item[8], red_bg)
elif not item[8] and not item[1]:
worksheet.write_string(row, col + 1, '', red_bg)
worksheet.write_string(row, col + 8, '', red_bg)
# If Solarwinds circuit ID not in the description
elif (item[8].lower() not in item[1].lower()):
worksheet.write_string(row, col + 1, item[1], red_bg)
worksheet.write_string(row, col + 8, item[8], red_bg)
else:
worksheet.write_string(row, col + 1, item[1])
worksheet.write_string(row, col + 8, item[8])
# Build Carrier check list
if item[11].lower() == 'verizon' or 'vzw':
carrier_list = ['verizon', 'vzw']
elif item[11].lower() == 'twt' or 'time warner telecom' or 'level3':
carrier_list = ['twt', 'time warner telecom', 'level3']
# If none of the carriers in carrier_list are in device description
if all(s not in item[1].lower() for s in carrier_list):
worksheet.write_string(row, col + 1, item[1], red_bg)
worksheet.write_string(row, col + 11, item[11], red_bg)
else:
worksheet.write_string(row, col + 1, item[1])
worksheet.write_string(row, col + 11, item[11])
worksheet.write_string(row, col + 5, item[5])
worksheet.write_string(row, col + 6, item[6])
worksheet.write_string(row, col + 7, item[7])
worksheet.write_string(row, col + 12, item[12])
worksheet.write_string(row, col + 13, item[13])
row += 1
workbook.close()
if __name__ == "__main__":
main()
线程功能:
from netmiko import ConnectHandler
import re
def compare(swis_result):
ios_username = 'user'
ios_password = 'pass'
bw_re = re.compile(r'bandwidth\s(\d*)')
desc_re = re.compile(r'description\s(.*)')
gi02_vlan_re = re.compile(r'GigabitEthernet0\/2(\.\d*)')
# gi02_down_re = re.compile(r'GigabitEthernet0\/2.*(down)')
gi000_re = re.compile(r'GigabitEthernet(0\/0\/0)')
goldcar_re = re.compile(r'VOICE-Q\n\s*priority\s(\d*)')
servicepolicy_re = re.compile(r'service-policy\soutput\s(\d*)')
serial_class_re = re.compile(r'class\s(\d*)')
router = {
'device_type': 'cisco_ios',
'ip': swis_result['Caption'],
'username': ios_username,
'password': ios_password,
'secret': ios_password,
'port': 22,
}
ssh_conn = ConnectHandler(**router)
ssh_conn.enable()
output = ssh_conn.send_command("sh ip int br")
try:
gi02_vlan = re.search(gi02_vlan_re, output).group(1)
except AttributeError:
gi02_vlan = ''
try:
tier1_bb_check = re.search(gi000_re, output).group(1)
except AttributeError:
tier1_bb_check = ''
while True:
if gi02_vlan:
output = ssh_conn.send_command("sh run int gi0/2{0}".format(gi02_vlan))
description = re.search(desc_re, output).group(1)
bandwidth = re.search(bw_re, output).group(1)
service_policy = re.search(servicepolicy_re, output).group(1)
break
else:
output = ssh_conn.send_command("sh run int gi0/2")
try:
description = re.search(desc_re, output).group(1)
bandwidth = re.search(bw_re, output).group(1)
try:
service_policy = re.search(servicepolicy_re, output).group(1)
except AttributeError:
service_policy = ""
break
break
except:
try:
output = ssh_conn.send_command("sh run int Multilink1")
description = re.search(desc_re, output).group(1)
bandwidth = re.search(bw_re, output).group(1)
service_policy = re.search(servicepolicy_re, output).group(1)
break
except AttributeError:
try:
output = ssh_conn.send_command("sh run int Serial0/0/0:1")
description = re.search(desc_re, output).group(1)
bandwidth = re.search(bw_re, output).group(1)
output = ssh_conn.send_command("sh run int Serial0/0/0:1.1")
service_policy = re.search(serial_class_re, output).group(1)
break
except AttributeError:
description = "?"
bandwidth = "?"
service_policy = "?"
break
if '01' in swis_result['Caption']:
output = ssh_conn.send_command('sh policy-map WAN-QOS-MAP')
goldcar = re.search(goldcar_re, output).group(1)
else:
goldcar = ''
vzb_list = ['vzn', 'verizon']
twt_list = ['time warner cable', 'twtcs']
if any(word in description.lower() for word in vzb_list):
carrier = 'VZB'
elif any(word in description.lower() for word in twt_list):
carrier = 'TWT'
spreadsheet_row = [swis_result['Caption'], description, bandwidth, service_policy, goldcar, carrier, '', '',
swis_result['CircuitID'], swis_result['Bandwidth'], swis_result['GOLDCAR'], swis_result['Carrier'], '', '']
return(spreadsheet_row)
答案 0 :(得分:0)
我必须在worker函数中放置一个ssh_conn.disconnect()才能正常关闭SSH连接。这是创建永不终止的额外线程的地方。