有用過Python開發UI的人應該都知道,Python的UI更新速度很慢,不是一般的慢,是超級慢。慢到時麼程度呢?大概就是你如果寫一個for迴圈更新比如20個Entry元件的文字顯示,會在UI上清楚的看到20個元件依序被刷新的畫面,20個更新完大概要1到2秒吧。
這樣的速度在有些需要即時反映且更新頻繁的案子上就會被客戶打槍了,因此有一個小方法雖然不能改變Python在UI上的更新速度,但至少可以不讓UI更新速度影響工作的進行 (UI它慢就慢,但我程序還是一樣照跑照跳)。
解法就是:
我們在程式運作一開始,就先產生兩個thread,一個負責程序的進行,一個負責UI的更新。
來看source code:
class EventHandleThread (threading.Thread):
def __init__(self, fun, name):
threading.Thread.__init__(self)
self.name = name
self.fun = fun
self.stopped = [0]
def run(self):
self.fun(self.name, self.stopped)
print ("Exiting " + self.name)
def stop(self):
self.stopped[0] = 1
#用來傳遞內容的Queue and Lock
m_queueLock = threading.Lock()
m_workQueue = queue.Queue(30)
#UI thread的運作function
def UiHandleLoop(self, name, stopped):
global m_queueLock , m_workQueue
print ('UiHandleLoop - Start')
while stopped[0] == 0:
m_queueLock.acquire()
if not m_workQueue.empty():
data = m_workQueue.get()
m_queueLock.release()
if data['cmd'] == '001':
(更新UI)
elif data['cmd'] == '002':
(更新UI)
elif data['cmd'] == '003':
(更新UI)
elif data['cmd'] == '004':
(更新UI)
else:
m_queueLock.release()
#主程序thread的運作function
def ProcessHandleLoop(self, name, stopped):
global m_queueLock , m_workQueue
print ('ProcessHandleLoop - Start')
while stopped[0] == 0:
#將要顯示到UI的資料放到Queue中
m_waferQueueLock.acquire()
m_waferWorkQueue.put({'cmd':'001','data':'testtestest'})
m_waferQueueLock.release()
global m_Threads
thread1 = EventHandleThread(self.ProcessHandleLoop, "Thread-ProcessHandle")
m_Threads.append(thread1)
m_Threads[0].start();
thread2 = EventHandleThread(self.UiHandleLoop, "Thread-UiHandleLoop")
m_Threads.append(thread2)
m_Threads[1].start();
global m_Threads
for i in range(len(m_Threads)):
print ('stop main thread...')
try:
if m_Threads[i].is_alive():
m_Threads[i].stop()
m_Threads[i].join()
except:
print ('main thread except')
pass
透過thread和Queue、Lock的運用,就可以將UI的更新和程序的運作分開,不讓UI更新拖累主程序了。
這樣的速度在有些需要即時反映且更新頻繁的案子上就會被客戶打槍了,因此有一個小方法雖然不能改變Python在UI上的更新速度,但至少可以不讓UI更新速度影響工作的進行 (UI它慢就慢,但我程序還是一樣照跑照跳)。
解法就是:
產生一個thread專門負責UI介面上的更新
我們在程式運作一開始,就先產生兩個thread,一個負責程序的進行,一個負責UI的更新。
來看source code:
class EventHandleThread (threading.Thread):
def __init__(self, fun, name):
threading.Thread.__init__(self)
self.name = name
self.fun = fun
self.stopped = [0]
def run(self):
self.fun(self.name, self.stopped)
print ("Exiting " + self.name)
def stop(self):
self.stopped[0] = 1
#用來傳遞內容的Queue and Lock
m_queueLock = threading.Lock()
m_workQueue = queue.Queue(30)
#UI thread的運作function
def UiHandleLoop(self, name, stopped):
global m_queueLock , m_workQueue
print ('UiHandleLoop - Start')
while stopped[0] == 0:
m_queueLock.acquire()
if not m_workQueue.empty():
data = m_workQueue.get()
m_queueLock.release()
if data['cmd'] == '001':
(更新UI)
elif data['cmd'] == '002':
(更新UI)
elif data['cmd'] == '003':
(更新UI)
elif data['cmd'] == '004':
(更新UI)
else:
m_queueLock.release()
#主程序thread的運作function
def ProcessHandleLoop(self, name, stopped):
global m_queueLock , m_workQueue
print ('ProcessHandleLoop - Start')
while stopped[0] == 0:
#將要顯示到UI的資料放到Queue中
m_waferQueueLock.acquire()
m_waferWorkQueue.put({'cmd':'001','data':'testtestest'})
m_waferQueueLock.release()
在程序一開始,產生執行這兩個thread:
global m_Threads
thread1 = EventHandleThread(self.ProcessHandleLoop, "Thread-ProcessHandle")
m_Threads.append(thread1)
m_Threads[0].start();
thread2 = EventHandleThread(self.UiHandleLoop, "Thread-UiHandleLoop")
m_Threads.append(thread2)
m_Threads[1].start();
在程序要結束前,關掉兩個thread:
global m_Threads
for i in range(len(m_Threads)):
print ('stop main thread...')
try:
if m_Threads[i].is_alive():
m_Threads[i].stop()
m_Threads[i].join()
except:
print ('main thread except')
pass
透過thread和Queue、Lock的運用,就可以將UI的更新和程序的運作分開,不讓UI更新拖累主程序了。
留言
張貼留言