Is it possible for some messagebus subscriblers to handle message in UI thread, some others in background thread? - reactiveui

I'm using ReactiveUI's RegisterScheduler like this:
MessageBus.Current.RegisterScheduler<string>(RxApp.MainThreadScheduler, someContract);
I want some of the message subscribers (who register this message) handle it in UI thread, but at the same time, some other subscribers handle it in backgroud thread.
Here is the use case: Some of the message's subscribers will handle UI related data which must happen in UI thread. But I want to reduce the UI thread usage as minimum as possible, so I would like to have other operations (not related to UI) happen in background thread. Is it possible for ReactiveUI?
My current solution is to use 2 different contract string, which in fact can be considered 2 different messages. It works, but both messages should be send out together, which makes me feel reduntent.
Any ideas?
Fei

Perhaps ignore the scheduler, or set maybe set your default appropriately (the default is CurrentThreadScheduler) and just use ObserveOn to define which scheduler the handler will be executed with when you need to.
To handle on the UI thread:
MessageBus.Current.Listen<string>()
.ObserveOn(RxApp.MainThreadScheduler)
.Subscribe(message => { /* ... */ });
To handle on a thread pool thread:
MessageBus.Current.Listen<string>()
.ObserveOn(RxApp.TaskpoolScheduler)
.Subscribe(message => { /* ... */ });

Related

How to handle 2 event source using 2 separate thread in golang

This is a design-related question. I have a situation where my application receives events from 2 different sources it is registered with and the application should handle events from these 2 sources parallelly. My Application is already handling events from one source using the buffered channel (where events are queued up and processed one after another). Now I am in a situation where the application needs to handle the events from a different source and I cannot use the same channel here because the Application may have to handle events from these 2 sources parallelly. I am thinking of using another buffered channel to handle the events from the second event source. But I am concerned about the same resource being used to process 2 events parallelly. Even though we use channel we need to again apply sync while processing these events.
Could you please suggest me a better way, any patterns I can use, or a design to handle this situation?
This is the code I have now to handle event from one source
for event := range thisObj.channel {
log.Printf("Found a new event '%s' to process at the state %s", event, thisObj.currentState)
stateins := thisObj.statesMap[thisObj.currentState]
// This is separate go routine. Hence acuire the lock before calling a state to process the event.
thisObj.mu.Lock()
stateins.ProcessState(event.EventType, event.EventData)
thisObj.mu.Unlock()
}
Here thisObj.channel is being created at start up and the events are being added in a separate method. Currently this method is reading events from the channel and processing the events.
You can use the for select pattern to read process your events from a single channel and process them in parallel:
var events *EventsChannel
for {
select {
case eventA = <-events:
// handle A
case eventB = <-events:
// handle B
default:
// unknown type, error case
}
}

How can I have multiple contexts handle events in Apama

I am trying to define a monitor in which I receieve events and then handle them on multiple contexts (roughly equating to threads if I understand correctly) I know I can write
spawn myAction() to myNewContext;
and this will run that action in the new context.
However I want to have an action which will respond to an event when it comes into my monitor:
on all trigger() as t {
doMyThing()
}
on all otherTrigger() as ot {
doMyOtherThing()
}
Can I define my on all in a way that uses a specific context? Something like
on all trigger() as t in myContext {
doMyThing()
}
on all otherTrigger() as t in myOtherContext {
doMyOtherThing()
}
If not what is the best way to define this in Apama EPL? Also could I have multiple contexts handling the same events when they arrive, round robin style?
Apama events from external receivers (ie the outside world) are delivered only to public contexts, including the 'main' context. So depending on your architecture, you can either spawn your action to a public context
// set the receivesInput parameter to true to make this context public
spawn myAction() to context("myContext", true);
...
action myAction() {
on all trigger() as t {
doMyThing();
}
}
or, spawn your action to a private context and set up an event forwarder in a public context, usually the main context (which will always exist)
spawn myAction() to context("myNewContext");
on all trigger() as t {
send t to "myChannel"; // forward all trigger events to the "myChannel" channel
}
...
action myAction() {
monitor.subscribe("myChannel"); // receive all events delivered to the "myChannel" channel
on all trigger() as t {
doMyThing();
}
}
Spawning to a private context and leveraging the channels system is generally the better design as it only sends events to contexts that care about them
To extend a bit on Madden's answer (I don't have enough rep to comment yet), the private context and forwarders is also the only way to achieve true round-robin: otherwise all contexts will receive all events. The easiest approach is to use a partitioning strategy (e.g. IDs ending in 0 go to context-0, or you have one context per machine you're monitoring, etc.), because then each concern is tracked in the same context and you don't have to share state.
Also could I have multiple contexts handling the same events when they arrive, round robin style?
This isn't entirely clear to me. What benefit are you aiming for here? If you're looking to reduce latency by having the "next available" context pick up the event, this probably isn't the right way to achieve it - the deciding which context processes the event means you'd need inter-context communications and coordination, which will increase latency. If you want multiple contexts to process the same events (e.g. one context runs your temperature spike rule, and another runs your long-term temperature average rule, but both take temperature readings as inputs), then that's a good approach but it's not what I'd have called round-robin.

Not receiving Apache Camel Event Notifications under the smallest load

I have extended EventNotiferSupport, and set the isEnable() to respond True for all events. I have a notify() that logs what events I receive and the corresponding Exchange ID for the event.
I have added my ExchangeMessageNotifier with this.context.getManagementStrategy().addEventNotifier(this.exchangeMessageNotifier);
I run my program under basically no load, sending 1 message at a time 1 second delay between messages into Camel to send out. Everything works the way I expect. I receive my events everything looks good.
I decrease the delay between messages to 0 milliseconds, and I find that 1 out of approximately 20 messages I fail to receive one of the Events, (Often the Completed event).
Add a second thread sending at the same rate and I don't get any events for any messages.
What am I missing? I've done searches and I don't find anything that I need to do differently. Is there something I am missing?
I am using Apache Camel 2.16.3, and moved to 2.18.1 still see the same behavior.
Well found my own answer. Part of the fun of inheriting code without any informaiton.
In your implementation of the EventNotifierSupport you need to override the doStart() method and configure the EventNotifierSupport for what events you wish to receive.
protected void doStart() throws Exception {
// filter out unwanted events
setIgnoreCamelContextEvents(true);
setIgnoreServiceEvents(true);
setIgnoreRouteEvents(true);
setIgnoreExchangeCreatedEvent(true);
setIgnoreExchangeCompletedEvent(false);
setIgnoreExchangeFailedEvents(true);
setIgnoreExchangeRedeliveryEvents(true);
setIgnoreExchangeSentEvents(false);
}
This is in addition to doing the following:
public boolean isEnabled(EventObject event) {
return true;
}
Which enables you to determine if you want a particular event, out of the selected groups you had set in the doStart().
Once these changes were in I was receiving consistent events.

Running Plone subscriber events asynchronously

In using Plone 4, I have successfully created a subscriber event to do extra processing when a custom content type is saved. This I accomplished by using the Products.Archetypes.interfaces.IObjectInitializedEvent interface.
configure.zcml
<subscriber
for="mycustom.product.interfaces.IRepositoryItem
Products.Archetypes.interfaces.IObjectInitializedEvent"
handler=".subscribers.notifyCreatedRepositoryItem"
/>
subscribers.py
def notifyCreatedRepositoryItem(repositoryitem, event):
"""
This gets called on IObjectInitializedEvent - which occurs when a new object is created.
"""
my custom processing goes here. Should be asynchronous
However, the extra processing can sometimes take too long, and I was wondering if there is a way to run it in the background i.e. asynchronously.
Is it possible to run subscriber events asynchronously for example when one is saving an object?
Not out of the box. You'd need to add asynch support to your environment.
Take a look at plone.app.async; you'll need a ZEO environment and at least one extra instance. The latter will run async jobs you push into the queue from your site.
You can then define methods to be executed asynchronously and push tasks into the queue to execute such a method asynchronously.
Example code, push a task into the queue:
from plone.app.async.interfaces import IAsyncService
async = getUtility(IAsyncService)
async.queueJob(an_async_task, someobject, arg1_value, arg2_value)
and the task itself:
def an_async_task(someobject, arg1, arg2):
# do something with someobject
where someobject is a persistent object in your ZODB. The IAsyncService.queueJob takes at least a function and a context object, but you can add as many further arguments as you need to execute your task. The arguments must be pickleable.
The task will then be executed by an async worker instance when it can, outside of the context of the current request.
Just to give more options, you could try collective.taskqueue for that, really simple and really powerful (and avoid some of the drawbacks of plone.app.async).
The description on PyPI already has enough to get you up to speed in no time, and you can use redis for the queue management which is a big plus.

What is considered overloading the main thread?

I am displaying information from a data model on a user interface. My current approach to doing so is by means of delegation as follows:
#protocol DataModelDelegate <NSObject>
- (void)updateUIFromDataModel;
#end
I am implementing the delegate method in my controller class as follows, using GCD to push the UI updating to the main thread:
- (void)updateUIFromDataModel {
dispatch_async(dispatch_get_main_queue(), ^{
// Code to update various UI controllers
// ...
// ...
});
}
What I am concerned about is that in some situations, this method can be called very frequently (~1000 times per second, each updating multiple UI objects), which to me feels very much like I am 'spamming' the main thread with commands.
Is this too much to be sending to the main thread? If so does anyone have any ideas on what would be the best way of approaching this?
I have looked into dispatch_apply, but that appears to be more useful when coalescing data, which is not what I am after - I really just want to skip updates if they are too frequent so only a sane amount of updates are sent to the main thread!
I was considering taking a different approach and implementing a timer instead to constantly poll the data, say every 10 ms, however since the data updating tends to be sporadic I feel that it would be wasteful to do so.
Combining both approaches, another option I have considered would be to wait for an update message and respond by setting the timer to poll the data at a set interval, and then disabling the timer if the data appears to have stopped changing. But would this be over-complicating the issue, and would the sane approach be to simply have a constant timer running?
edit: Added an answer below showing the adaptations using a dispatch source
One option is to use a Dispatch Source with type DISPATCH_SOURCE_TYPE_DATA_OR which lets you post events repeatedly and have libdispatch combine them together for you. When you have something to post, you use dispatch_source_merge_data to let it know there's something new to do. Multiple calls to dispatch_source_merge_data will be coalesced together if the target queue (in your case, the main queue) is busy.
I have been experimenting with dispatch sources and got it working as expected now - Here is how I have adapted my class implementation in case it is of use to anyone who comes across this question:
#implementation AppController {
#private
dispatch_source_t _gcdUpdateUI;
}
- (void)awakeFromNib {
// Added the following code to set up the dispatch source event handler:
_gcdUpdateUI = dispatch_source_create(DISPATCH_SOURCE_TYPE_DATA_ADD, 0, 0,
dispatch_get_main_queue());
dispatch_source_set_event_handler(_gcdUpdateUI, ^{
// For each UI element I want to update, pull data from model object:
// For testing purposes - print out a notification:
printf("Data Received. Messages Passed: %ld\n",
dispatch_source_get_data(_gcdUpdateUI));
});
dispatch_resume(_gcdUpdateUI);
}
And now in the delegate method I have removed the call to dispatch_async, and replaced it with the following:
- (void)updateUIFromDataModel {
dispatch_source_merge_data(_gcdUpdateUI, 1);
}
This is working absolutely fine for me. Now Even during the most intense data updating the UI stays perfectly responsive.
Although the printf() output was a very crude way of checking if the coalescing is working, a quick scrolling back up the console output showed me that the majority of the messages print outs had a value 1 (easily 98% of them), however there were the intermittent jumps to around 10-20, reaching a peak value of just over 100 coalesced messages around a time when the model was sending the most update messages.
Thanks again for the help!
If the app beach-balls under heavy load, then you've blocked the main thread for too long and you need to implement a coalescing strategy for UI updates. If the app remains responsive to clicks, and doesn't beach-ball, then you're fine.

Resources