Основная проблема заключается в том, что ping -w 1000
требует много времени для запуска, но Pool.map()
ждет всех результатов. Вы даже можете запустить results = p.map(...)
без queue
(но с return result
), но он также может заблокировать tkinter
Вы можете использовать map_async()
, чтобы запустить его, не дожидаясь результатов.
Я также использую starmap
(или скорее starmap_async()
) для отправки двух аргументов ip, queue
каждому процессу.
Я также внес другие изменения - ie. переименуйте переменные, переместите код в __init__
, чтобы создать только один раз (изображения, Pool
, Queue
). Я также отправляю список IP в другое окно в качестве аргумента Window2(master, data)
и обратно Window1(master, data)
- поэтому я могу редактировать этот список.
BTW:
, потому что я запускаю Linux, поэтому я изменил аргументы для ping
и проверьте другой текст, чтобы проверить, получил ли он ответ.
import os
import multiprocessing.dummy
import queue
import tkinter as tk
import tkinter.ttk as ttk
# --- classes ---
class Window1:
def __init__(self, master, data=None):
self.master = master
self.data = data
if self.data is None:
self.data = []
self.text = tk.Text(self.master, height=20, width=50)
self.text.grid(row=1, column=1)
self.button = tk.Button(self.master, height=3, width=10, text="OK", command=self.new_window)
self.button.grid(row=2, column=1)
# put self.data in Text
#for item in self.data:
# self.text.insert('end', item + '\n')
self.text.insert('end', '\n'.join(self.data))
def new_window(self):
text = self.text.get('1.0', 'end')
# remove empty lines
self.data = [item.strip() for item in text.split("\n") if item.strip()]
self.master.destroy()
root = tk.Tk()
Window2(root, self.data)
root.mainloop()
class Window2:
def __init__(self, master, data):
self.master = master
# keep list
self.data = data
# create dictionary for results
self.results = {ip: [ip, '???'] for ip in self.data}
self.button = tk.Button(self.master, height=2, width=11, text='New', command=self.new)
self.button.grid(row=0, column=0, sticky='w')
self.label = tk.Label(self.master, text='monitor', font=("Arial", 20))
self.label.grid(row=0, column=1)
cols = ('IP','Result')
self.treeview = ttk.Treeview(self.master, columns=cols)
for col in cols:
self.treeview.heading(col, text=col)
self.treeview.column(col,minwidth=0,width=170)
self.treeview.grid(row=1, column=0, columnspan=3)
# create only once
self._image_green = None # tk.PhotoImage(file="green1.gif")
self._image_red = None # tk.PhotoImage(file="red.gif")
# to reduce number of processes for small `data`
n = min(5, len(self.data))
# create only once
self.queue = queue.Queue()
self.num_threads = n * multiprocessing.cpu_count()
self.p = multiprocessing.dummy.Pool(self.num_threads)
# to stop `after()`
self.running = True
# run first time
self.update_treeview() # to display it before running processes
self.run_processes()
self.processes_incoming() # first create window to display it faster
def run_processes(self):
if self.running:
self.p.starmap_async(self.ping, [(ip, self.queue) for ip in self.data])
self.after_ID2 = self.master.after(500, self.run_processes)
def ping(self, ip, queue):
#print('start ping:', ip)
#cmd = 'ping -n 1 -w 3 ' + ip
cmd = 'ping -w 1 ' + ip # Linux
child_stdout = os.popen(cmd)
result = child_stdout.readlines()
child_stdout.close()
#print('end ping:', ip)
#if any('Reply from' in line for line in result):
if any('bytes from' in line for line in result): # Linux
value = [ip, 'success']
else:
value = [ip, 'failed']
queue.put(value)
def update_treeview(self):
self.treeview.delete(*self.treeview.get_children())
for ip in self.data:
ip, value = self.results[ip]
if value == 'success':
image = self._image_green
elif value == 'failed':
image = self._image_red
else:
image = None
#self.treeview.insert('', 'end', image=image, value=(ip, valueb))
self.treeview.insert('', 'end', value=(ip, value))
def processes_incoming(self):
if self.running:
# get all from queue
new_values = False
while self.queue.qsize():
#while not self.queue.empty:
data = self.queue.get_nowait()
ip, value = data
self.results[ip] = data
new_values = True
# update only if new values
if new_values:
self.update_treeview()
# repeate after 100ms
self.after_ID1 = self.master.after(100, self.processes_incoming)
def new(self):
# to stop all `after()`
self.running = False
self.master.after_cancel(self.after_ID1)
self.master.after_cancel(self.after_ID2)
self.master.destroy()
root = tk.Tk()
Window1(root, self.data)
root.mainloop()
# --- functions ---
def main():
examples = [
'127.0.0.1', # localhost
'10.0.0.1', # IP in local network
'192.168.0.1', # IP in local network
'8.8.8.8', # Google DNS
'8.8.4.4', # Google DNS
]
root = tk.Tk()
Window1(root, examples)
root.mainloop()
# --- main ---
if __name__ == '__main__':
main()