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