Synchronous and Asynchronous callbacks

Eko palypse ekopalypse at gmail.com
Mon Sep 30 07:00:27 EDT 2019


Am Montag, 30. September 2019 11:46:43 UTC+2 schrieb Barry Scott:
> > On 29 Sep 2019, at 21:41, Eko palypse <ekopalypse at gmail.com> wrote:
> > 
> > Am Sonntag, 29. September 2019 19:18:32 UTC+2 schrieb Barry Scott:
> >>> On 29 Sep 2019, at 14:14, Eko palypse <ekopalypse at gmail.com> wrote:
> >>> 
> >>> Unfortunately, I can't make all callbacks synchronous or asynchronous because this has negative effects on the application in one way or another.
> >> 
> >> Surely you can make all callbacks async?
> >> You do not have to have them wait, they can complete their work in one call.
> >> 
> >> sync == async-that-does-not-await
> >> 
> >> Barry
> > 
> > Thank you for your answer but I'm sorry I don't get it. 
> > What do you mean by I don't have to have them wait?
> > 
> > Let me explain my understanding, with some pseudo code, how async callbacks
> > works and please keep in mind that I'm a novice when it comes to OO designs
> > and basic software design strategies/techniques, so I might be totally
> > wrong about what I'm doing.
> 
> When you said async I thought you meant the specific programming model in Python
> that uses "async def", "await" etc. You are using threads.
> 
> The problem you are facing is that the UI must not become unresponsive.
> Further a background thread cannot call any UI framework functions as the UI
> framework can only be called on the main thread.
> 
> You can run fast event handers on the UI thread but slow running handlers
> must be run on another thread to allow the UI to be responsive.
> 
> What I do is have the event handler for a long running task take the responsibility
> to queue the task onto a background thread. While the task is running it sends status
> to the UI thread so that UI elements are updated (progress bars, etc).
> 
> If you are using PyQt5 you might find the code I used for SCM Workbench interesting.
> 
> I can write event handlers that look like this:
> 
> @thread_switcher
> def eventHandler( self, ... ):
> 	# starts in the foreground (UI thread)
> 	self.status.update('Working...')
> 
> 	yield self.switchToBackground
> 	# now on the background thread
> 	self.doSlowTask()
> 
> 	yield self.switchToForeground
> 	# now in the foreground
> 	self.status.update('Done')
> 
> The code is in:
> 
> https://github.com/barry-scott/scm-workbench/blob/master/Source/Common/wb_background_thread.py
> 
> @thread_switcher adds an attribute to the function so the rest of the
> code knows this is an event handler that needs to use a background thread.
> 
> When I add an event handler I call through a function (wrapWithThreadSwitcher)
> that wraps only functions that have been marked with @thread_switcher.
> 
> The rest of the code is the machinery to handle moving between threads via the generator.
> 
> Barry
> 
> > 
> > An SYNCHRONOUS callback is like this. Event/notification gets fired and
> > notification handler calls all registered methods one after the other.
> > Something like
> > 
> > if notification.list_of_methods:
> >    for method in list_of_methods:
> >        method()
> > 
> > whereas an ASYNCHRONOUS callback is more like this. Event/notification gets
> > fired and notification handler informs another thread that the event has
> > been fired and all registered async callback methods should get executed.
> > So something like this
> > 
> > class EventThread(threading.Thread):
> >    def __init__(...):
> >        super()...
> >        self.event = threading.Event()
> >        self.kill = False
> >        ...
> >    def run(self):
> >        while True:
> >            self.event.wait()
> >            self.event.clear()
> >            if not self.kill:
> >                for method in self.list_of_methods:
> >                    method()
> > 
> > et = EventThread()
> > if notification.list_of_methods:
> >    et.event.set()  # run all async methods
> >    for method in list_of_methods:  # run sync methods
> >        method())
> > 
> > 
> > So if there is no synchronous callback for that notification then the 
> > notification handler would just set the event and return. 
> > The EventThread would then call one registered callback after the other.
> > Right?
> > 
> > Using this approach does sound fine from UI point of view as there is
> > minimal impact and UI keeps responsive but from code execution point of view
> > it sound much more complicated. What if one async callback is slow or buggy?
> > This could lead to unpredictable behavior where as in a synchronous execution you immediately know what is causing it. 
> > That was the reason I decided not to offer async callbacks until I 
> > discovered that other parts, like UI modifications aren't working properly.
> > And there are notification which must be called in a synchronous way, like
> > the modification event. If you want to intercept a modification safely then it can only be done within a synchronous callback. 
> > 
> > Does this makes sense to you? Or do I have wrong understanding or, again, an
> > wrong assumption how this works?
> > 
> > Thank you
> > Eren
> > -- 
> > https://mail.python.org/mailman/listinfo/python-list
> >

Thank you very much, this sounds like what I'm looking for and I'm sure I find tons of other useful information/techniques which I'm not aware of yet.

Thank you
Eren



More information about the Python-list mailing list