python response slow when running external DLL

Peter Otten __peter__ at web.de
Tue Dec 1 06:01:14 EST 2015


jfong at ms4.hinet.net wrote:
> Peter Otten at 2015年11月28日 UTC+8 6:14:09PM wrote:
>> No, the point of both recipes is that tkinter operations are only ever
>> invoked from the main thread. The main thread has polling code that
>> repeatedly looks if there are results from the helper thread. As far I
>> understand the polling method has the structure
>>>> f():
>> # did we get something back from the other thread?
>> # a queue is used to avoid race conditions
>>>> # if yes react.
>> # var_status.set() goes here
>>>> # reschedule f to run again in a few millisecs;
>> # that's what after() does
>> Have no idea how the main thread poll on all those events (or it use a
> queue)? All I know now is that the main thread(mainloop()?) can be easily
> blocked by event handlers if the handler didn't run as a separate thread.
>>> > .....
>> > .....
>> > #do the rest
>> > var_status.set('Download...')
>> > _thread.start_new_thread(td_download, ()) #must use threading
>> > 
>> > def td_download():
>> > result = mydll.SayHello()
>> > if result:
>> > var_status.set("Download Fail at %s" % hex(result))
>> > showerror('Romter', 'Download Fail')
>> > else:
>> > var_status.set('Download OK')
>> > showinfo('Romter', 'Download OK')
>>>> As td_download() runs in the other thread the var_status.set() methods
>> are problematic.
>> No idea what kind of problem it will encounter. Can you explain?

While the var_status.set() invoked from the second thread modifies some 
internal data the main thread could kick in and modify (parts of) that same 
data, thus bringing tkinter into an broken state. A simple example that 
demonstrates the problem:
import random
import threading
import time
account = 70
def withdraw(delay, amount):
 global account
 if account >= amount:
 print("withdrawing", amount)
 account -= amount
 else:
 print("failed to withdraw", amount)
threads = []
for i in range(10):
 t = threading.Thread(
 target=withdraw,
 kwargs=dict(delay=.1,
 amount=random.randrange(1, 20)))
 threads.append(t)
 t.start()
for t in threads:
 t.join()
Before every withdrawal there seems to be a check that ensures that there is 
enough money left, but when you run the script a few times you will still 
sometimes end with a negative balance. That happens when thread A finds 
enough money, then execution switches to thread B which also finds enough 
money, then both threads perform a withdrawal -- oops there wasn't enough 
money for both.
 
>> Another complication that inevitably comes with concurrency: what if the
>> user triggers another download while one download is already running? If
>> you don't keep track of all downloads the message will already switch to
>> "Download OK" while one download is still running.
>> Hummm...this thought never comes to my mind. After take a quick test I
> found, you are right, a second "download" was triggered immediately.
> That's a shock to me. I suppose the same event shouldn't be triggered
> again, or at least not triggered immediately, before its previous handler
> was completed. ...I will take a check later on Borland C++ builder to see
> how it reacts!
>> Anyway to prevent this happens? if Python didn't take care it for us.

A simple measure would be to disable the button until the download has 
ended.


More information about the Python-list mailing list

AltStyle によって変換されたページ (->オリジナル) /