I'm having a problem that I can't figure out how to solve. Probably the solution is also simple, but at the moment it does not appear in my head. Ah, I didn't know what to write in the title, so if you want to change how you think it's lawful, do it =)
I put a simplified version of the code, where the problem appears:
from pyglet.gl import *
import threading, time, os
FPS = 120.0
class ucgm(pyglet.window.Window):
window_on_show = False
grid_set = 32, 18
old_set = 1024, 576
new_set = old_set
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.__video_set()
self.__resource = Resource_Load(self)
s_l = threading.Thread(target=self.__resource.start_load())
s_l.start()
def on_show(self):
print("1")
self.window_on_show = True
print("2")
def on_draw(self):
self.clear()
def update(self, dt):
pass
def on_close(self):
os._exit(0)
def __video_set(self):
self.__platform = pyglet.window.get_platform()
self.__default_display = self.__platform.get_default_display()
self.__default_screen = self.__default_display.get_default_screen()
self.set_size(self.new_set[0], self.new_set[1])
self.location = self.__default_screen.width // 2 - self.new_set[0] // 2, self.__default_screen.height // 2 - self.new_set[1] // 2
self.set_location(self.location[0], self.location[1])
class Resource_Load():
def __init__(self, main):
self.engine = main
self.loop_load = True
def start_load(self):
while self.loop_load:
if self.engine.window_on_show:
self.loop_load = False
print("3")
else:
print("4")
time.sleep(1)
print("5")
if __name__ == "__main__":
uc = ucgm()
pyglet.clock.schedule_interval(uc.update, 1 / FPS)
pyglet.app.run()
Before talking about the problem, I would like to explain what my intention was. What I thought was to create a class parallel to the main one that took care of loading all the resources used. In the meantime, it had to "dialogue" with the main class and modify a variable of it that showed the progress of the upload. Some time ago I asked a similar question on Stackoverflow about something similar (Link Question). The difference is that in that question the parallel function was internal to the main class. But given the amount of resources to load, I decided to dedicate a separate class to him. Once everything was written, I thought of another problem. Although it was written later, the Thread started before the window appeared completely. I thought of adding a simple time.sleep set with a few seconds. But then I reasoned that there was the possibility of a delay, caused by excessive use of RAM by the user, and therefore the time set was not sufficient. So I modified, adding a while loop with the condition that if the window was visible, it would have ended the loop and continued loading, otherwise it would have waited a second. nd here we are finally in the problem. The script as it is written does not work. Or rather, it remains stuck in the cycle, despite being open in a Thread. I knew, from my previous question, that the Thread should not directly touch Pyglet, and in fact it does not happen, since it is only reading the status of a variable. So I don't understand why I'm getting this result. The cycle seems to be not happening in parallel and therefore blocks the on_show function which fails to update the variable and thus to break the cycle. Do you have any suggestions for me to solve the problem I'm having? Thanks for your help
Instead of passing a reference to the start_load function on this line:
s_l = threading.Thread(target=self.__resource.start_load())
...that line is actually calling that function (notice the ()), which is running that infinite loop on the main thread. Get rid of that (); threading.Thread will do the call for you:
s_l = threading.Thread(target=self.__resource.start_load)
Additionally, there are better ways to wait for something to happen in one thread from another. You should consider using one of the thread synchronization object provided in Python, for example, a threading.Event:
class ucgm(pyglet.window.Window):
window_opened = threading.Event()
// ...
def on_show(self):
self.window_opened.set()
// ...
class Resource_Load():
// ...
def start_load(self):
self.engine.window_opened.wait()
print("done")
// ...
Related
I am trying to run a function in the background till some work is done in the main function and then finish the thread. I have implemented the threading logic in a separate class and the main in another file. But every time I run it the target function only seems to run once and then waits
Here is the main function
from ThreadRipper import *
thread_obj=ThreadRipper()
thread_obj.start_thread()
squish.snooze(10)
print("Main Continuing")
thread_obj.stop_thread()
And the implemented class is as follows
class ThreadRipper():
def __init__(self):
lib_path="iCOMClient.dll"
self.vx = IcomVx(lib_path)
config = ConfigParser.SafeConfigParser(allow_no_value=True)
config.readfp(open("vx_logger_config.cfg"))
self.vx.connect(config.get("icom","ip"), timeout_millis = 30000)
self.t = threading.Thread(target=self.task_to_do, args=(self.vx,))
def stop_thread(self):
self.t.do_run=False
self.t.join()
def start_thread(self):
self.t.start()
def task_to_do(self,arg):
current_thread=threading.currentThread()
while getattr(current_thread,"do_run",True):
with open("vx.txt",'a') as f:
f.write(str(arg.get_next_message()._rawmsg)+"\n")
time.sleep(1)
print("Stopping")
arg.disconnect()
When I run this I get the vx file created but with only one entry, I expect it to be written to continuously till the while loop exits. I am quite new at threading and may have understood it incorrectly. Please advise
Thank you
The reason is probably because
print("Stopping")
arg.disconnect()
are both inside the while loop. After disconnecting, arg doesn't seem to produce any more messages.
(Unless, of course, your code in the question is not what you really have, but in this case, you surely would have edited your question so it matches.)
I'm very new to python development, I need to call a function every x seconds.
So I'm trying to use a timer for that, something like:
def start_working_interval():
def timer_tick():
do_some_work() // need to be called on the main thread
timer = threading.Timer(10.0, timer_tick)
timer.start()
timer = threading.Timer(10.0, timer_tick)
timer.start()
the do_some_work() method need to be called on the main thread, and I think using the timer causing it to execute on different thread.
so my question is, how can I call this method on the main thread?
I'm now sure what you trying to achive but i played with your code and did this:
import threading
import datetime
def do_some_work():
print datetime.datetime.now()
def start_working_interval():
def timer_tick():
do_some_work()
timer = threading.Timer(10.0, timer_tick)
timer.start()
timer_tick()
start_working_interval()
So basically what i did was to set the Time inside the timer_tick() so it will call it-self after 10 sec and so on, but i removed the second timer.
I needed to do this too, here's what I did:
import time
MAXBLOCKINGSECONDS=5 #maximum time that a new task will have to wait before it's presence in the queue gets noticed.
class repeater:
repeatergroup=[] #our only static data member it holds the current list of the repeaters that need to be serviced
def __init__(self,callback,interval):
self.callback=callback
self.interval=abs(interval) #because negative makes no sense, probably assert would be better.
self.reset()
self.processing=False
def reset(self):
self.nextevent=time.time()+self.interval
def whennext(self):
return self.nextevent-time.time() #time until next event
def service(self):
if time.time()>=self.nextevent:
if self.processing=True: #or however you want to be re-entrant safe or thread safe
return 0
self.processing==True
self.callback(self) #just stuff all your args into the class and pull them back out?
#use this calculation if you don't want slew
self.nextevent+=self.interval
#reuse this calculation if you do want slew/don't want backlog
#self.reset()
#or put it just before the callback
self.processing=False
return 1
return 0
#this the transition code between class and classgroup
#I had these three as a property getter and setter but it was behaving badly/oddly
def isenabled(self):
return (self in self.repeatergroup)
def start(self):
if not (self in self.repeatergroup):
self.repeatergroup.append(self)
#another logical place to call reset if you don't want backlog:
#self.reset()
def stop(self):
if (self in self.repeatergroup):
self.repeatergroup.remove(self)
#group calls in c++ I'd make these static
def serviceall(self): #the VB hacker in me wants to name this doevents(), the c hacker in me wants to name this probe
ret=0
for r in self.repeatergroup:
ret+=r.service()
return ret
def minwhennext(self,max): #this should probably be hidden
ret=max
for r in self.repeatergroup:
ret=min(ret,r.whennext())
return ret
def sleep(self,seconds):
if not isinstance(threading.current_thread(), threading._MainThread): #if we're not on the main thread, don't process handlers, just sleep.
time.sleep(seconds)
return
endtime=time.time()+seconds #record when caller wants control back
while time.time()<=endtime: #spin until then
while self.serviceall()>0: #service each member of the group until none need service
if (time.time()>=endtime):
return #break out of service loop if caller needs control back already
#done with servicing for a while, yield control to os until we have
#another repeater to service or it's time to return control to the caller
minsleeptime=min(endtime-time.time(),MAXBLOCKINGPERIOD) #smaller of caller's requested blocking time, and our sanity number (1 min might be find for some systems, 5 seconds is good for some systems, 0.25 to 0.03 might be better if there could be video refresh code waiting, 0.15-0.3 seems a common range for software denouncing of hardware buttons.
minsleeptime=self.minwhennext(minsleeptime)
time.sleep(max(0,minsleeptime))
###################################################################
# and now some demo code:
def handler1(repeater):
print("latency is currently {0:0.7}".format(time.time()-repeater.nextevent))
repeater.count+=repeater.interval
print("Seconds: {0}".format(repeater.count))
def handler2(repeater): #or self if you prefer
print("Timed message is: {0}".format(repeater.message))
if repeater.other.isenabled():
repeater.other.stop()
else:
repeater.other.start()
repeater.interval+=1
def demo_main():
counter=repeater(handler1,1)
counter.count=0 #I'm still new enough to python
counter.start()
greeter=repeater(handler2,2)
greeter.message="Hello world." #that this feels like cheating
greeter.other=counter #but it simplifies everything.
greeter.start()
print ("Currently {0} repeaters in service group.".format(len(repeater.repeatergroup)))
print("About to yield control for a while")
greeter.sleep(10)
print("Got control back, going to do some processing")
time.sleep(5)
print("About to yield control for a while")
counter.sleep(20) #you can use any repeater to access sleep() but
#it will only service those currently enabled.
#notice how it gets behind but tries to catch up, we could add repeater.reset()
#at the beginning of a handler to make it ignore missed events, or at the
#end to let the timing slide, depending on what kind of processing we're doing
#and what sort of sensitivity there is to time.
#now just replace all your main thread's calls to time.sleep() with calls to mycounter.sleep()
#now just add a repeater.sleep(.01) or a while repeater.serviceall(): pass to any loop that will take too long.
demo_main()
There's a couple of odd things left to consider:
Would it be better to sort handlers that you'd prefer to run on main thread from handlers that you don't care? I later went on to add a threadingstyle property, which depending on it's value would run on main thread only, on either main thread or a shared/group thread, or stand alone on it's own thread. That way longer or more time-sensitive tasks, could run without causing the other threads to be as slowed down, or closer to their scheduled time.
I wonder whether, depending on the implementation details of threading: is my 'if not main thread: time.sleep(seconds); return' effectively make it sufficiently more likely to be the main thread's turn, and I shouldn't worry about the difference.
(It seems like adding our MAXBLOCKINGPERIOD as the 3rd arg to the sched library could fix it's notorious issue of not servicing new events after older longer in the future events have already hit the front of the queue.)
This question already has answers here:
Run certain code every n seconds [duplicate]
(7 answers)
Closed 8 years ago.
I have a threaded class whose loop needs to execute 4 times every second. I know that I can do something like
do_stuff()
time.sleep(0.25)
but the problem is that is doesn't account for the time it takes to do_stuff(). Effectively this needs to be a real-time thread. Is there a way to accomplish this? Ideally the thread would still be put to sleep when not executing code.
The simple solution
import threading
def work ():
threading.Timer(0.25, work).start ()
print "stackoverflow"
work ()
The above will make sure that work is run with an interval of four times per second, the theory behind this is that it will "queue" a call to itself that will be run 0.25 seconds into the future, without hanging around waiting for that to happen.
Because of this it can do it's work (almost) entirely uninterrupted, and we are extremely close to executing the function exactly 4 times per second.
More about threading.Timer can be read by following the below link to the python documentation:
docs.python.org - 16.2.7. Timer Objects
RECOMMENDED] The more advanced/dynamic solution
Even though the previous function works as expected you could create a helper function to aid in dealing with future timed events.
Something as the below will be sufficient for this example, hopefully the code will speak for itself - it is not as advanced as it might appear.
See this as an inspiration when you might implement your own wrapper to fit your exact needs.
import threading
def do_every (interval, worker_func, iterations = 0):
if iterations != 1:
threading.Timer (
interval,
do_every, [interval, worker_func, 0 if iterations == 0 else iterations-1]
).start ()
worker_func ()
def print_hw ():
print "hello world"
def print_so ():
print "stackoverflow"
# call print_so every second, 5 times total
do_every (1, print_so, 5)
# call print_hw two times per second, forever
do_every (0.5, print_hw)
I did a bit different approach with one Thread, looping in a while loop.
For me the advantages are:
Only one Thread, the other solutions mentioned here starting and stopping threads for every interval
More control for the Interval, you are able to stop the IntervalTimer with .stop() method
Code:
from threading import Thread, Event
# StoppableThread is from user Dolphin, from http://stackoverflow.com/questions/5849484/how-to-exit-a-multithreaded-program
class StoppableThread(Thread):
def __init__(self):
Thread.__init__(self)
self.stop_event = Event()
def stop(self):
if self.isAlive() == True:
# set event to signal thread to terminate
self.stop_event.set()
# block calling thread until thread really has terminated
self.join()
class IntervalTimer(StoppableThread):
def __init__(self, interval, worker_func):
super().__init__()
self._interval = interval
self._worker_func = worker_func
def run(self):
while not self.stop_event.is_set():
self._worker_func()
sleep(self._interval)
Usage:
def hw():
print("Hello World")
interval = IntervalTimer(1,hw)
interval.start()
sleep(10)
interval.stop()
I have a QThread which runs, but will often need to be killed, then recreated. The problem is I'm getting an untraceable TypeError that pops up and I have no idea what's causing it. I presume I'm not exiting the thread properly or destroying it properly or some such sillyness, but I just haven't a clue what's causing it. Here's some code snippets:
Here's the code together:
class getHistory(QThread):
def __init__(self):
QThread.__init__(self)
self.killSwitch = 0
def kill(self):
self.killSwitch = 1
self.wait()
def run(self):
try:
for x in theloop:
hist = QTreeWidgetItem()
hist.data = dataStuff
self.emit(SIGNAL('histItem'), hist)
if self.killSwitch == 1: break
except: pass
self.emit(SIGNAL('string'), 'done')
return
class Main(QtGui.QMainWindow):
def __init__(self, args):
QtGui.QMainWindow.__init__(self)
self.runTheThread()
def doFunction(self, string):
if not string == 'done':
doThreadStuff
else:
doFinishedThreadStuff
def runTheThread(self):
self.theThread= getHistory()
self.connect(self.theThread, QtCore.SIGNAL("string"), self.doFunction)
self.theThread.start()
Then to try to kill it before looping, I kill theThread with self.theThread.kill()
All the proper things as far as killing the thread appear to be happening, except, if the thread is killed and restarted fast enough, I'll get an untraceable error:
TypeError: doFunction() takes exactly 2 arguments (1 given)
Also, on a slightly related note, is it wise/smart/right to check if a thread is done by emitting a string such as "Done" that is picked up by doFunction, or is there a better way to do it?
As doFunction is part of a Qt application, the two parameters are self, string. The code works until it is spammed, really, and only then does it present the error.
Thanks in advance.
Well, as error states clearly: You are sending self.doFunction just one parameter (the string "AllDone" in this case):
self.emit(SIGNAL('string'), 'AllDone')
but, I'll take a wild guess (since you didn't share the definition of doFunction) that it is defined as taking two parameters. So, anytime you emit the "string" signal you are bound to get that error.
As for the signal, if it's sole purpose is to shout that the thread is completed its run, QThread already has a "finished()" signal that is emitted when run is completed. Just use that.
On a side note: If you are using PyQt4.5+ consider using new-style signal and slots. They are more pythonic.
I'm having some problems threading my pyGTK application. I give the thread some time to complete its task, if there is a problem I just continue anyway but warn the user. However once I continue, this thread stops until gtk.main_quit is called. This is confusing me.
The relevant code:
class MTP_Connection(threading.Thread):
def __init__(self, HOME_DIR, username):
self.filename = HOME_DIR + "mtp-dump_" + username
threading.Thread.__init__(self)
def run(self):
#test run
for i in range(1, 10):
time.sleep(1)
print i
..........................
start_time = time.time()
conn = MTP_Connection(self.HOME_DIR, self.username)
conn.start()
progress_bar = ProgressBar(self.tree.get_widget("progressbar"),
update_speed=100, pulse_mode=True)
while conn.isAlive():
while gtk.events_pending():
gtk.main_iteration()
if time.time() - start_time > 5:
self.write_info("problems closing connection.")
break
#after this the program continues normally, but my conn thread stops
Firstly, don't subclass threading.Thread, use Thread(target=callable).start().
Secondly, and probably the cause of your apparent block is that gtk.main_iteration takes a parameter block, which defaults to True, so your call to gtk.main_iteration will actually block when there are no events to iterate on. Which can be solved with:
gtk.main_iteration(block=False)
However, there is no real explanation why you would use this hacked up loop rather than the actual gtk main loop. If you are already running this inside a main loop, then I would suggest that you are doing the wrong thing. I can expand on your options if you give us a bit more detail and/or the complete example.
Thirdly, and this only came up later: Always always always always make sure you have called gtk.gdk.threads_init in any pygtk application with threads. GTK+ has different code paths when running threaded, and it needs to know to use these.
I wrote a small article about pygtk and threads that offers you a small abstraction so you never have to worry about these things. That post also includes a progress bar example.