Flutter: send message to isolate without `await` - flutter

The title is one way of doing what I ultimately want; others may be acceptable.
So I have a class that already exists. It controls some other stuff, and has a start and stop method. We are now making the list of "other stuff" depend on some settings saved in shared preferences, but shared preferences requires an asynchronous SharedPreferences.getInstance() call. I don't want to have to propagate asynchronicity all the way up the call chain. How do I avoid that? (Alternative 1: is there a library that you can persist data with, without messing directly with asynchronicity?)
Part of the problem is that the start and stop methods can be called at any point after the constructor (and indeed, when I just did SharedPreferences.getInstance().then(INITIALIZE LATE FINAL FIELDS), without await, start got called before the initialization happened and the code threw an exception.
(Alternative 2: is it acceptable to save the result of a then, and later call then on it? Like, do this._future = SharedPreferences.getInstance().then((prefs) {return LIST_OF_STUFF;}), and in start do this._future.then((listOfStuff) {START LIST OF STUFF; return listOfStuff;}), and similarly in stop? Seems...suspicious, but possibly functional.) I'd be ok with making the start and stop methods asynchronous, I guess, as long as I don't have to actually handle that in the code that calls them, but that doesn't really solve the problem that I need the SharedPreferences.getInstance() to have completed so I can have the list of stuff, first.
My default mechanism for handling concurrency is Communicating Sequential Processes, so I took a leaf from that book and thought, "What if I started an isolate that accepts start/stop messages? It can await the SharedPreferences, then loop over incoming messages and start/stop the Stuff as requested. I wrote an isolate to do that...and apparently you can't pass a ReceivePort in to an isolate (at least not by declaring it in the outer scope and using the reference in the isolate - it gives me an error Invalid argument(s): Illegal argument in isolate message: (object is aReceivePort)). You only get to directly hand the isolate a SendPort, so IT can send THE CALLER messages. The idiom I see in most places is to have the isolate send back a new SendPort, whose ReceivePort the isolate keeps. However, this returns me to my original problem - creating the isolate (and receiving its SendPort) is asynchronous, so it may not be done by the time start or stop get called. Since you pretty clearly CAN send a ReceivePort between...wait, I forgot it's technically not sending a ReceivePort, just another SendPort. Can you really only send SendPorts, specifically? That's...really obnoxious, if so. It seems pointlessly pedantic and obstructive. ...Ok, yeah, ReceivePort is explicitly restricted from being sent. Argh. I even thought I had a workaround to the "can't pass via scope" problem: make a new ReceivePort in the calling code, use its SendPort to send start and stop messages, and jerryrig some kind of handover of the ReceivePort to the isolate once that comes online. But if ReceivePort is entirely forbidden from being sent to the isolate, I guess that's out. So...how do I do what I want to do??? How do I pull a setting from disk, potentially queuing up start and stop messages while I wait for the persistence library to become available, without exposing to the calling code that we're making asynchronous calls under the hood?? Am I gonna have to make some kind of awful kludge of dangerous asynchronously-modified flags? I'll be rather disappointed in Flutter if that's what it comes down to.

Related

I am having a problem with Flutter/Dart Async code execution, as in how does it work

In Flutter we use async await and Future, can someone explain that if we don't use another thread (which we can't in dart) and run the job on main UIThread only won't the app become choppy because even if we are waiting for the job to execute it will ultimately execute on UIThread only.
I somewhere read about isolates also. But cannot paint the exact picture. If someone can explain in detail.
I think you missed something when it comes to asynchronous methods in Dart.
Dart is a single-threaded programming language, Java or C# are multi-threaded programming languages, forget async as a new thread, it doesn't happen in Dart.
Dart is a single-threaded programming language. This means is that Dart can only run one instruction at a time, while Java could run multiple instructions concurrently.
As a rule, everything you do in Dart will start in UI-Thread. Whatever method you call in Dart, whether using sync, async, then, they will be running on UI-Thread, since Dart is a single thread.
In single-threaded languages ​​like Javascript and Dart, an async method is NOT executed in parallel but following the regular sequence of events, handled by the Event Loop. There are some problems (I would give some approaches, as we will see below) if you run the following code in a multithreaded language where fetch will take some time to execute:
String user = new Database.fetch(David);
String personalData = new Database.fetch(user);
You will receive David's data in user, and after that, you will receive your data.
This will lock your UI, unlike languages ​​like Java which have Threads, where you can perform this task in the background, on another thread, and the UI-Thread will run smoothly.
If you do this at Dart
String user = new Database.fetch(David);
String personalData = new Database.fetch(user);
user will be null in personalData, because the fetch event is a Future.
How to solve this in Dart?
String user = await Database.fetch(David);
String personalData = await Database.fetch(user);
For those who like a more functional paradigm (I don't like it) you can use then.
Database.fetch(David).then((user){
Database.fetch(user).then((personal){
String personalData = personal;
});
});
However, imagine that you have billions of data in that database, this heavy task will probably cause the animations on your screen to freeze, and you will see a jank in the user's UI, for that purpose isolates were invented.
Dart Isolates give you a way to perform real multi-threading in Dart. They have their own separate heaps(memory), and run the code in the background, just like the Threads of multi-threaded languages. I could explain how isolates work, but it would make this response very long, and the goal is just to differentiate asynchronous from multi-threaded methods.
A simple way to solve the problem above using isolates would be using compute.
Compute was created to facilitate the creation of isolates, you just pass the function and the data that this function will execute, and that's it!
Important to remember that compute is a Future, so you have to use await or then to get its result.
In our example, we could create a new thread and get its result when we finish by just calling compute like this:
String user = await compute(Database.fetch,David);
String personalData = await compute(Database.fetch,user);
Very simple, isn't it?
In summary:
Everything that waits some time to be completed, in Dart is called a "Future".
To wait for the result of a future to be assigned to a variable, use await or then.
The asynchronous methods (await and then) can be used to obtain a result from a Future, and are executed ON THE MAIN THREAD because Dart is single-thread.
If you want to run any function on a new thread, you can create an isolate. Dart offers an easy-to-use isolate wrapper called compute, where you only need to pass one method that will be processed and the data that will be processed, and it will return its result in the future.
NOTE: if you are going to use compute make sure you are using a static or top-level method (see that in the example I used Database.fetch it was no accident if you need to call Database().fetch or need to create an instance of it, means it is not a static method and will not work with isolates).
English is not my first language and I didn't want to write so much because of that, but I hope I helped differentiate between multi-threaded asynchronous programming from single-threaded asynchronous programming.

Dart/Flutter: How to best process hardware events in an infinite loop

I have an infinite loop that runs in a an async function in a Flutter application (although the code is pure Dart, no Flutter API is used on it).
Basically, it processes some math stuff, but I want to be able to update the data to be processed with an event coming from hardware (in this specific case from the microphone).
In order to give the fast while(true) the opportunity to get events from the outside, I added a delay with a duration of zero.
doStuff() async {
while (!stopFlag) {
processMathStuff(dataModifiedByHardwareCallback);
// Without this, the loop can't be interrupted.
await Future.delayed(Duration.zero);
}
}
And although that seems to work in most platforms, calling Future.delayed like that makes this loop much slower than I would like. The question is if is it there a better (faster) way of doing this. This even looks kind of a hack to me. I tried calling Future.delayed only every a certain amount of iterations, but doing so even as often as every 10 iterations, the system loses events.
By the way, processMathStuff does not contain loops internally, so it is really O(1).
NOTE: If I move the code to an Isolate, I get a similar problem with the Isolate not listening to the sendPort stuff if the while(true) lacks that kind of "yield".

Why does `libpq` use polling rather than notification for data fetch?

I am reading libpq reference. It has both of sync and async methods. Bu I discovered something strange.
When I see PQsendQuery function, it seems to send a query and return immediately. And I expected a callback function to get notified, but there was no such thing and the manual says to poll for data availability.
I don't understand why async method is written in polling way. Anyway, as libp is the official client implementation, I believe there should be a good reason for this design. What is that? Or am I missing correct callback stuffs mentioned somewhere else?
In the execution model of a mono-threaded program, the execution flow can't be interrupted by data coming back from an asynchronous query, or more generally a network socket. Only signals (SIGTERM and friends) may interrupt the flow, but signals can't be hooked to data coming in.
That's why having a callback to get notified of incoming data is not possible. The piece of code in libpq that would be necessary to emit the callback would never run if your code doesn't call it. And if you have to call it, that defeats the whole point of a callback.
There are libraries like Qt that provide callbacks, but they're architectured from the ground up with a main loop that acts as an event processor. The user code is organized in callbacks and event-based processing of incoming data is possible. But in this case the library takes ownership of the execution flow, meaning its mainloop polls the data sources. That just shifts the responsibility to another piece of code outside of libpq.
This page is describing how I can get be notified for async result fetch.
http://www.postgresql.org/docs/9.3/static/libpq-events.html#LIBPQ-EVENTS-PROC
PGEVT_RESULTCREATE
The result creation event is fired in response to any query execution
function that generates a result, including PQgetResult. This event
will only be fired after the result has been created successfully.
typedef struct {
PGconn *conn;
PGresult *result; } PGEventResultCreate; When a PGEVT_RESULTCREATE event is received, the evtInfo pointer should be cast to a
PGEventResultCreate *. The conn is the connection used to generate the
result. This is the ideal place to initialize any instanceData that
needs to be associated with the result. If the event procedure fails,
the result will be cleared and the failure will be propagated. The
event procedure must not try to PQclear the result object for itself.
When returning a failure code, all cleanup must be performed as no
PGEVT_RESULTDESTROY event will be sent.

How to request a replay of an already received fix message

I have an application that could potentitally throw an error on receiving a ExecutionReport (35=8) message.
This error is thrown at the application level and not at the fix engine level.
The fix engine records the message as seen and therefore will not send a ResendRequest (35=2). However the application has not processed it and I would like to manually trigger a re-processing of the missed ExecutionReport.
Forcing a ResendRequest (35=2) does not work as it requires modifying the expected next sequence number.
I was wonderin if FIX supports replaying of messages but without requiring a sequence number reset?
When processing an execution report, you should not throw any exceptions and expect FIX library to handle it. You either process the report or you have a system failure (i.e. call abort()). Therefore, if your code that handles execution report throws an exception and you know how to handle it, then catch it in that very same function, eliminate the cause of the problem and try processing again. For example (pseudo-code):
// This function is called by FIX library. No exceptions must be thrown because
// FIX library has no idea what to do with them.
void on_exec_report(const fix::msg &msg)
{
for (;;) {
try {
// Handle the execution report however you want.
handle_exec_report(msg);
} catch(const try_again_exception &) {
// Oh, some resource was temporarily unavailable? Try again!
continue;
} catch(const std::exception &) {
// This should never happen, but it did. Call 911.
abort();
}
}
}
Of course, it is possible to make FIX library do a re-transmission request and pass you that message again if exception was thrown. However, it does not make any sense at all because what is the point of asking the sender (over the network, using TCP/IP) to re-send a message that you already have (up your stack :)) and just need to process. Even if it did, what's the guarantee it won't happen again? Re-transmission in this case is not only doesn't sound right logically, the other side (i.e. exchange) may call you up and ask to stop doing this crap because you put too much load on their server with unnecessary re-transmit (because IRL TCP/IP does not lose messages and FIX sequence sync process happens only when connecting, unless of course some non-reliable transport is used, which is theoretically possible but doesn't happen in practice).
When aborting, however, it is FIX library`s responsibility not to increment RX sequence unless it knows for sure that user has processed the message. So that next time application starts, it actually performs synchronization and receives missing messages. If QuickFIX is not doing it, then you need to either fix this, take care of this manually (i.e. go screw with the file where it stores RX/TX sequence numbers), or use some other library that handles this correctly.
This is the wrong thing to do.
A ResendRequest tells the other side that there was some transmission error. In your case, there wasn't, so you shouldn't do that. You're misusing the protocol to cover your app's mistakes. This is wrong. (Also, as Vlad Lazarenko points out in his answer, if they did resend it, what's to say you won't have the error again?)
If an error occurs in your message handler, then that's your problem, and you need to find it and fix it, or alternately you need to catch your own exception and handle it accordingly.
(Based on past questions, I bet you are storing ExecutionReports to a DB store or something, and you want to use Resends to compensate for DB storage exceptions. Bad idea. You need to come up with your own redundancy solution.)

In Scala, does Futures.awaitAll terminate the thread on timeout?

So I'm writing a mini timeout library in scala, it looks very similar to the code here: How do I get hold of exceptions thrown in a Scala Future?
The function I execute is either going to complete successfully, or block forever, so I need to make sure that on a timeout the executing thread is cancelled.
Thus my question is: On a timeout, does awaitAll terminate the underlying actor, or just let it keep running forever?
One alternative that I'm considering is to use the java Future library to do this as there is an explicit cancel() method one can call.
[Disclaimer - I'm new to Scala actors myself]
As I read it, scala.actors.Futures.awaitAll waits until the list of futures are all resolved OR until the timeout. It will not Future.cancel, Thread.interrupt, or otherwise attempt to terminate a Future; you get to come back later and wait some more.
The Future.cancel may be suitable, however be aware that your code may need to participate in effecting the cancel operation - it doesn't necessarily come for free. Future.cancel cancels a task that is scheduled, but not yet started. It interrupts a running thread [setting a flag that can be checked]... which may or may not acknowledge the interrupt. Review Thread.interrupt and Thread.isInterrupted(). Your long-running task would normally check to see if it's being interrupted (your code), and self-terminate. Various methods (i.e. Thread.sleep, Object.wait and others) respond to the interrupt by throwing InterruptedException. You need to review & understand that mechanism to ensure your code will meet your needs within those constraints. See this.