python - How can I stop a long-running function when it is called multiple times? -


below have example program. when button pressed, takes second before can calculate value show. if user presses button in rapid succession end waiting long time see last answer, answer care about. in code, can see _datacruncher function needs know self._count, self._count not depend on output of _datacruncher.

my question, therefore, how can interrupt normal execution of _datacruncher on subsequent calls in order keep gui free other stuff, , not waste processing time when not needed? realize need use thread run _datacruncher , sort of queue appropriate val display, not understand how put together.

from pyqt4 import qtgui, qtcore import sys import time import random import random  class mainwindow(qtgui.qmainwindow):     def __init__(self):         self.app = qtgui.qapplication(sys.argv)         super(mainwindow, self).__init__()         self.count = 0         self.initui()      def initui(self):         # layouts         central = qtgui.qwidget()         layout = qtgui.qvboxlayout()          self.button = qtgui.qpushbutton('press me')         self.text = qtgui.qlabel('?')          layout.addwidget(self.button)         layout.addwidget(self.text)          central.setlayout(layout)         self.setcentralwidget(central)          self.button.clicked.connect(self._buttonclicked)      def _datacruncher(self, val):         time.sleep(1) # takes long time process data using val         return val * random.randint(1,10)      def _buttonclicked(self):         self.count += 1         val = self._datacruncher(self.count)         self.text.settext('value {}'.format(val))      def startup(self):         self.show()         result = self.app.exec_()         sys.exit(result)  if __name__ == '__main__':     random.seed()     mywindow = mainwindow()     mywindow.startup() 

so, finding answer more complicated thought. @mtset mentions in 1 of comments, python not offer means cancel execution of thread. so, did create 'threadhandler' class that, well, handles thread. keeps track of last thread created , offers means result execution of last thread.

i posting modified version of test code original post threadhandler code in full in case has use it.

file 1 here

# tester.py, run file  pyqt4 import qtgui, qtcore import random, sys, time threadhandler import mythreadhandler  class mymodel(object):     def datacruncher(self, val):         delay = random.randint(1,5)         print('{} sleeping {}'.format(val, delay))         time.sleep(delay) # takes long time process data using val         print('{} done sleeping'.format(val))         return val  class mainwindow(qtgui.qmainwindow):     def __init__(self, threadhandler):         self.app = qtgui.qapplication(sys.argv)         super(mainwindow, self).__init__()         self.count = 0         self.initui()         self.button_clicked_events = event()         self.threadhandler = threadhandler      def initui(self):         # layouts         central = qtgui.qwidget()         layout = qtgui.qvboxlayout()          self.button = qtgui.qpushbutton('press me')         self.text = qtgui.qlabel('?')          layout.addwidget(self.button)         layout.addwidget(self.text)          central.setlayout(layout)         self.setcentralwidget(central)          self.button.clicked.connect(self._buttonclicked)      def _buttonclicked(self):         self.count += 1         self.button_clicked_events(self.count)      def setlabel(self, val):         self.text.settext(str(val))      def startup(self):         self.show()         result = self.app.exec_()         return result   class event(list):     """event subscription.      list of callable objects. calling instance of cause     call each item in list in ascending order index.      example usage:     >>> def f(x):     ...     print 'f(%s)' % x     >>> def g(x):     ...     print 'g(%s)' % x     >>> e = event()     >>> e()     >>> e.append(f)     >>> e(123)     f(123)     >>> e.remove(f)     >>> e()     >>> e += (f, g)     >>> e(10)     f(10)     g(10)     >>> del e[0]     >>> e(2)     g(2)      """     def __init__(self):         self.output = {}      def __call__(self, *args, **kwargs):         f,key in self:             output = f(*args, **kwargs)             self.output[key] = output         return self.output     def __repr__(self):         return "event({})".format(list.__repr__(self))  if __name__ == '__main__':     def checker(handler, window):         if handler.islastdone():             val = handler.getlastresult()             window.setlabel(val)         else:             window.setlabel('calculating...')      random.seed()     model = mymodel()     threadhandler = mythreadhandler()     mywindow = mainwindow(threadhandler)      threadhandler.createtimer(1, checker, threadhandler, mywindow)      def getdata(count):         threadhandler.createoneshot(model.datacruncher, count)      mywindow.button_clicked_events.append((getdata, 'dt'))      result = mywindow.startup()     print('ending')     threadhandler.end()     print('ended')     sys.exit(result) 

file 2 below

#threadhandler.py, save file in same folder tester.py  import threading, time  class mythreadhandler(object):     def __init__(self):         self.oneshots = []         self.timers = []         self.oldoneshots = []         self.latest = none         self.cleaning = false          self._startcleaner()      def _startcleaner(self):         print('-'*20+'starting cleaner'+'-'*20)         self.cleaner = self.createtimer(1, self._cleanupthreads)      def _stopcleaner(self):         print('-'*20+'stopping cleaner'+'-'*20)         self.cleaner.stop()      def getnumthreads(self):         return len(self.oneshots)      def getnumoldthreads(self):         return len(self.oldoneshots)      def end(self):         i,timer in enumerate(self.timers):             timer.stop()             self.timers.pop(i)      def createtimer(self, interval, func, *args, **kwargs):         timer = mytimer(interval, func, args, kwargs)         self.timers.append(timer)         return timer      def createoneshot(self, func, *args, **kwargs):         oneshot = myoneshot(func, args, kwargs)         self.oneshots.append(oneshot)         self.latest = oneshot      def islastdone(self):         if not self.latest none:             return not self.latest.running()         else:             return none      def getlastresult(self):         if self.latest none:             raise valueerror('there have not been oneshots created.')         while self.latest.running():             pass         result = self.latest.getresult()         if len(self.oneshots) > 0:             self.oldoneshots.append(myoneshot(self._cleanall, (self.oneshots,)))         self.oneshots = []         return result      def _cleanall(self, toclean):         # loop through toclean , pop that's done. lock         while len(toclean) > 0:             toclean = self._cleanup(toclean)      def _cleanup(self, tocleanup):         while not self.cleaning:             self.cleaning = true             i, thread in enumerate(tocleanup):                 if not thread.running():                     tocleanup.pop(i)         self.cleaning = false         return tocleanup      def _cleanupthreads(self):         # check each of these lists , pop out threads done.         # not lock. function should called         # cleaner, set in __init__         self.oneshots = self._cleanup(self.oneshots)         self.timers = self._cleanup(self.timers)         self.oldoneshots = self._cleanup(self.oldoneshots)  class mytimer(object):     def __init__(self, delay, func, args=tuple(), kwargs={}):         self.delay  = delay         self.func   = func         self.loop   = true         self.args   = args         self.kwargs = kwargs         self.thread = threading.thread(target=self.run, daemon=true)         self.thread.start()         self.output = none      def run(self):         while self.loop:             self.output = self.func(*self.args, **self.kwargs)             if self.delay > 0.1:                 count = 0                 while count <= self.delay:                     count += 0.1                     time.sleep(0.1)             else:                 time.sleep(self.delay)      def stop(self):         self.loop = false      def running(self):         return self.loop      def getresult(self):         return self.output  class myoneshot(object):     def __init__(self, func, args=tuple(), kwargs={}):         self.func = func         self.args = args         self.kwargs = kwargs         self.thread = threading.thread(target=self.run, daemon=true)         self.thread.start()         self.output = none      def run(self):         self.output = self.func(*self.args, **self.kwargs)      def running(self):         return self.thread.is_alive()      def getresult(self):         return self.output  if __name__ == '__main__':     import random     random.seed()      def longfunc(num):         delay = random.randint(5,8)         if num in (3, 6):             delay = 2         print('-'*30+'func {} has sleep {}'.format(num, delay))         time.sleep(delay)         print('-'*30+'func {} done'.format(num))         return num      def checker(handler):         if handler.islastdone():             return handler.getlastresult()         else:             return none      myhandler = mythreadhandler()      # 'checker' function simulates in program uses     # data generated 'longfunc'. waits until there no more threads     # in threadhandler, indicate user done     # switching back-and-forth between different values     checktimer = myhandler.createtimer(1, checker, myhandler)      # create 10 one-shot threads take 'long' time. delay keep     # them in order, loop meant simulate user switching between     # items using keyboard or mouse, imagine couldn't     # faster every 1/10th of second     start = time.time()     in range(4):         myhandler.createoneshot(longfunc, i)         time.sleep(0.1)      # wait until there no more threads executing     last = myhandler.getlastresult()      print('result last = {}'.format(last))      in range(4, 7):         myhandler.createoneshot(longfunc, i)         time.sleep(0.1)      last = myhandler.getlastresult()     print('result last = {}'.format(last))      while myhandler.getnumoldthreads() >0 or myhandler.getnumthreads() > 0:         pass      myhandler.end()     print('done ending') 

Comments

Popular posts from this blog

java - nested exception is org.hibernate.exception.SQLGrammarException: could not extract ResultSet Hibernate+SpringMVC -

sql - Postgresql tables exists, but getting "relation does not exist" when querying -

asp.net mvc - breakpoint on javascript in CSHTML? -