RxJava - why is my switchMap() so slow to switch? - javafx

I made an interesting discovery at work, and I'm hoping one of the RxJava gurus can explain it. I'm using RxJava 1.2.4.
I was using RxJavaFX to emit table selection events from a JavaFX TableView (these emit on the JavaFX thread), and put them in a switchMap()to kick off an expensive process for each one. I use the switchMap() with a subscribeOn() inside to not only leverage concurrency, but also if I rapidly make multiple selections, the previous requests are cancelled and the latest one starts next.
tableSelectionEvents.switchMap {
runExpensiveProcess(it)
.subscribeOn(Schedulers.io())
.flatMap { anotherExpensiveProcess(it) }
.toList()
}.observeOn(JavaFxScheduler.getInstance()).subscribe {
backingList.setAll(it)
}
However, I noticed the JavaFX UI was horribly laggy as I made selections, meaning the JavaFX thread was still doing a significant amount of work. This puzzled me because I thought I used the Schedulers.io() inside the switchMap() to offload the work on another thread, and indeed this was the case. But something else was going on.
I had a hunch and then put an observeOn(Schedulers.io()) right before the switchMap(). Now everything runs perfectly and there is no lag at all. My theory is that the incoming thread (originally the JavaFX thread, now the IO thread), has to do substantial work in cancelling the last subscription inside the switchMap(). This made the JavaFX thread spend a significant amount of time executing the cancellation and thus freezing up the UI.
Is calling unSubscribe() within the switchMap() that expensive?

I got some assistance from Jake Wharton on another forum. He highlighted what I was already starting to suspect. Some subscriptions are more expensive than others to unsubscribe. In this case, I think my usage of RxJava-JDBC resulted in a lot of query overhead that needed to be disposed, and the JavaFX thread became occupied doing this.
He also told me this is what the unsubscribeOn() operator is for. It allows specifying a scheduler for the execution of the unsubscription.
tableSelectionEvents.switchMap {
runExpensiveProcess(it)
.subscribeOn(Schedulers.io())
.flatMap { anotherExpensiveProcess(it) }
.toList()
.unsubscribeOn(Schedulers.io())
}.observeOn(JavaFxScheduler.getInstance()).subscribe {
backingList.setAll(it)
}

Related

Efficiently connecting an asynchronous IMFSourceReader to a synchronous IMFTransform

Given an asynchronous IMFSourceReader connected to a synchronous only IMFTransform.
Then for the IMFSourceReaderCallback::OnReadSample() callback is it a good idea not to call IMFTransform::ProcessInput directly within OnReadSample, but instead push the produced sample onto another queue for another thread to call the transforms ProcessInput on?
Or would I just be replicating identical work source readers typically do internally? Or put another way does work within OnReadSample run the risk of blocking any further decoding work within the source reader that could have otherwise happened more asynchronously?
So I am suggesting something like:
WorkQueue transformInputs;
...
// Called back async
HRESULT OnReadSampleCallback(... IMFSample* sample)
{
// Push sample and return immediately
Push(transformInputs, sample);
}
// Different worker thread awoken for transformInputs queue samples
void OnTransformInputWork()
{
// Transform object is not async capable
transform->TransformInput(0, Pop(transformInputs), 0);
...
}
This is touched on, but not elaborated on here 'Implementing the Callback Interface':
https://learn.microsoft.com/en-us/windows/win32/medfound/using-the-source-reader-in-asynchronous-mode
Or is it completely dependent on whatever the source reader sets up internally and not easily determined?
It is not a good idea to perform a long blocking operation in IMFSourceReaderCallback::OnReadSample. Nothing is going to be fatal or serious but this is not the intended usage.
Taking into consideration your previous question about audio format conversion though, audio sample data conversion is fast enough to happen on such callback.
Also, it is not clear or documented (depends on actual implementation), ProcessInput is often instant and only references input data. ProcessOutput would be computationally expensive in this case. If you don't do ProcessOutput right there in the same callback you might run into situation where MFT is no longer accepting input, and so you'd have to implement a queue anyway.
With all this in mind you would just do the processing in the callback neglecting performance impact assuming your processing is not too heavy, or otherwise you would just start doing the queue otherwise.

Can I delay/bundle reactions to QPlainTextEditor.textChanged events?

I have a small IDE for a modeling language I wrote, implemented in PyQt/PySide, and am trying to implement a code navigator that let's you jump to different sections in the file being edited.
The current implementation is: (1) connect to QPlainTextEditor.textChanged, (2) any time a change is made, (sloppily) parse the file and update the navigator pane
It seems to work OK, but I'm worried this could cause major performance issues for large files on slower systems, in particular if more stuff is connected to textChanged in the future.
My question: Has anybody here implemented a delayed reaction to events, so that multiple events (i.e. keystrokes) within a short period only trigger a single update (say once per second)? And is there a proper QT way of doing this?
Thanks,
Michael
You can try using timers if you want some "delay".
There would be 2 ways to use them (with different results).
One is only parse after no input has been done for a certain amount of time
NOTE: I only know C++ Qt but I assume the same things are valid for pyqt so this is kind of "pseudocode" I hope you get the concept though.
QTimer timer; //somewhere
timer.setSingleShot(true); //only fire once
connect(timer,QTimer::timeout(),OnTimerDone(...);
OnTextChanged(...)
{
timer.start(500); //wait 500ms
}
OnTimerDone(...)
{
DoStuff(...);
}
This will restart the timer every input, so when you call that and the timer is not done the timeout signal is not emitted. When no input is done for an amount of time the timer timeouts and you parse the file.
The second option would be to have a periodic timer running (singleShot(false)).
Just start the timer for like each second. and timeout will be called once a second. You can combine that with a variable which you set to true when the input changes and to false when the file is parsed. So you avoid parsing when nothing has changed.
In C++Qt you won't have to worry about multi-threading because the slot gets called in the GUI thread. I assume it is the same for python but you should probably check this.

Does returning VFW_S_CANT_CUE from IMediaFilter::GetState have any negative consequences

This MSDN page describes the need for some filters to return VFW_S_CANT_CUE from GetState() in the paused state if there's a possibility that the filter can't deliver while paused. That all seems clear enough. It seems if there's any doubt for a particular then it's probably better to return VFW_S_CANT_CUE to make sure that Pause() doesn't hang.
Delivering Samples
Are there any downsides to returning VFW_S_CANT_CUE though? Is resuming streaming from the paused state likely to perform poorly or lose sync if a mux or demux filter in the graph returns VFW_S_CANT_CUE?
I've inherited source code for several filters that sometimes return VFW_S_CANT_CUE for reasons that aren't clear to me (for example only returning VFW_S_CANT_CUE if no output samples have been delivered). I'm wondering if there any risks from always returning VFW_S_CANT_CUE.
Return of VFW_S_CANT_CUE disables synchronization with renderers during stopped/paused transition: Filter Graph Manager is not waiting for renderers to report that they are ready, which in case of video renderer means that it receives a banner frame and presents it (I suppose with sending EC_PAUSED notification). Disabled synchronization means that IMediaControl::Pause returns immediately and does not wait for banner frame, what live sources might prefer to do.
The only downside I can think of is that having Pause call completed you cannot be sure that video renderer presents valid frame and not blackness instead. I suppose the unclear reasoning behind VFW_S_CANT_CUE you are seeing is attempts of the developer to avoid deadlocks he stumbled on during debugging.
If filter returns VFW_S_CANT_CUE in GetState() method (i.e. LiveSource), Pause() method will not wait for samples to be queued. And because of this, stream time startd when filter graph is started.
Otherwise, filter graph will wait until several samples have been queued. And only after that stream time will be started (because after Pause(), Run() method called)

Main loop in event-driven programming and alternatives

To the best of my knowledge, event-driven programs require a main loop such as
while (1) {
}
I am just curious if this while loop can cost a high CPU usage? Is there any other way to implement event-driven programs without using the main loop?
Your example is misleading. Usually, an event loop looks something like this:
Event e;
while ((e = get_next_event()) != E_QUIT)
{
handle(e);
}
The crucial point is that the function call to our fictitious get_next_event() pumping function will be generous and encourage a context switch or whatever scheduling semantics apply to your platform, and if there are no events, the function would probably allow the entire process to sleep until an event arrives.
So in practice there's nothing to worry about, and no, there's not really any alternative to an unbounded loop if you want to process an unbounded amount of information during your program's runtime.
Usually, the problem with a loop like this is that while it's doing one piece of work, it can't be doing anything else (e.g. Windows SDK's old 'cooperative' multitasking). The next naive jump up from this is generally to spawn a thread for each piece of work, but that's incredibly dangerous. Most people would end up with an executor that generally has a thread pool inside. Then, the handle call is actually just enqueueing the work and the next available thread dequeues it and executes it. The number of concurrent threads remains fixed as the total number of worker threads in the pool and when threads don't have anything to do, they are not eating CPU.

Qt: setting an override cursor from a non-GUI thread

A while ago I wrote a little RAII class to wrap the setOverrideCursor() and restoreOverrideCursor() methods on QApplication. Constructing this class would set the cursor and the destructor would restore it. Since the override cursor is a stack, this worked quite well, as in:
{
CursorSentry sentry;
// code that takes some time to process
}
Later on, I found that in some cases, the processing code would sometimes take a perceptible time to process (say more than half a second) and other times it would be near instantaneous (because of caching). It is difficult to determine before hand which case will happen, so it still always sets the wait cursor by making a CursorSentry object. But this could cause an unpleasant "flicker" where the cursor would quickly turn from the wait cursor to the normal cursor.
So I thought I'd be smart and I added a separate thread to manage the cursor override. Now, when a CursorSentry is made, it puts in a request to the cursor thread to go to the wait state. When it is destroyed it tells the thread to return to the normal state. If the CursorSentry lives longer than some amount of time (50 milliseconds), then the cursor change is processed and the override cursor is set. Otherwise, the change request is discarded.
The problem is, the cursor thread can't technically change the cursor because it's not the GUI thread. In most cases, it does happen to work, but sometimes, if I'm really unlucky, the call to change the cursor happens when the GUI thread gets mixed in with some other X11 calls, and the whole application gets deadlocked. This usually only happens if the GUI thread finishes processing at nearly the exact moment the cursor thread decides to set the override cursor.
So, does anyone know of a safe way to set the override cursor from a non-GUI thread. Keep in mind that most of the time, the GUI thread is going to be busy processing stuff (that's why the wait cursor is needed after all), so I can't just put an event into the GUI thread queue, because it won't be processed until its too late. Also, it is impractical to move the processing I'm talking about to a separate thread, because this is happening during a paint event and it needs to do GUI work when its done (figuring out what to draw).
Any other ideas for adding a delay to setting the override cursor would be good, too.
I don't think there is any other way besides a Signal-Slot connection going to the GUI thread followed by a qApp->processEvents() call, but like you said, this would probably not work well when the GUI thread is tied up.
The documentation for QCoreApplication::processEvents also has some recommended usages with long event processing:
This function overloads processEvents(). Processes pending events for
the calling thread for maxtime milliseconds or until there are no more
events to process, whichever is shorter.
You can call this function
occasionally when you program is busy doing a long operation (e.g.
copying a file).
Calling this function processes events only for the
calling thread.
If possible break up the long calls in the paint event and have it periodically check to see how long it has been taking. And in any of those checks, have it set the override cursor then from in the GUI Thread.
Often a QProgressBar can go a long way to convey the same information to the user.
Another option that could help quite a bit would be to render outside of the GUI thread onto a QImage buffer and then post it to the GUI when it is done.

Resources