I'm lost on the distinction between posting using strand::wrap and a strand::post? Seems like both guarantee serialization yet how can you serialize with wrap and not get consistent order? Seems like they both would have to do the same thing. When would I use one over the other?
Here is a little more detail pseudo code:
mystrand(ioservice);
mystrand.post(myhandler1);
mystrand.post(myhandler2);
this guarantees my two handlers are serialized and executed in order even in a thread pool.
Now, how is that different from below?
ioservice->post(mystrand.wrap(myhandler1));
ioservice->post(mystrand.wrap(myhandler2));
Seems like they do the same thing?
Why use one over the other? I see both used and am trying to figure out when
one makes more sense than the other.
wrap creates a callable object which, when called, will call dispatch on a strand. If you don't call the object returned by wrap, nothing much will happen at all. So, calling the result of wrap is like calling dispatch. Now how does that compare to post? According to the documentation, post differs from dispatch in that it does not allow the passed function to be invoked right away, within the same context (stack frame) where post is called.
So wrap and post differ in two ways: the immediacy of their action, and their ability to use the caller's own context to execute the given function.
I got all this by reading the documentation.
This way
mystrand(ioservice);
mystrand.post(myhandler1);
mystrand.post(myhandler2);
myhandler1 is guaranteed by mystrand to be executed before myhandler2
but
ioservice->post(mystrand.wrap(myhandler1));
ioservice->post(mystrand.wrap(myhandler2));
the execution order is the order of executing wrapped handlers, which io_service::post does not guarantee.
Related
In a Rust application that is:
Synchronous in the sense of not using "async"
multi-threaded using std::thread
threads are communicating via channels
the "anyhow" crate is being used to annotate and propagate Results
I am propagating all errors up to the main thread, but I only see the Error that is hit by the main thread. This usually happens before I join the child threads, so I don't see the actual root cause.
What minimum-boilerplate modification can I make to see the Errors from multiple threads?
(I'll put some ideas I have in answers, but I'm hoping there is something better.)
I could use my main thread only for supervising child threads, aggregate all of their Results in some kind of Vec as I join them, filter it, and write custom code to print it.
This still feels like more work than should be necessary; I'm not the first person to write a threaded rust application that handles errors.
I could let threads panic and "propagate the panics":
https://doc.rust-lang.org/beta/std/thread/type.Result.html
But this is ugly:
It introduces a difference between how errors are handled in child threads vs. the main thread.
At every fallible call site in my original code I have to add .unwrap().
If I unwrap() every error in the child threads, I might as well not even be using Result error handling, because everything will be returning Ok() or panicking. If I make that transformation, then I change the signature of all my existing functions, which is also gross.
One option would be to upgrade the entire application to use a logging framework, and then scrape through the logs.
This will require modifications everywhere have added an anyhow .context(), ensure!, or bail! annotation, to conditionally also throw a logger error.
Eventually I will want both logging/telemetry and clean teardown from propagating Results, but even then I will not want to have several lines of boilerplate for every single fallible function call.
In Linux one is able to asynchronously read from a file by calling aio_read(3) from C. A sigevent structure is one of the parameters and there are different options one can specify to be notified when the operation is complete. Let me summarize:
SIGEV_NONE no notification.
The status can be checked with aio_error(3). The operation is async, but completion must be busily awaited in some loop which is not what I want.
SIGEV_SIGNAL a signal is raised to the process.
In theory, this can be caught in Haskell by installing a signal handler via System.Posix.Signals. There is a problem though: the API of SignalInfo doesn't include the crucial si_value that let's one communicate some specifics about the read request, like a StaticPtr. This is unfortunate.
SIGEV_THREAD this would start a new thread, according to the documentation.
I don't know how to represent this in Haskell. My best guess would be an IO () action. I'm not sure how to write the accompanying native code.
How can I use aio_read or something of that sort in Haskell? I will probably not get around using FFI on this (or a library).
I am trying to achieve a fire-and-forget call of an output function with can take any time.
The caller is not interested at all whether this function is successful or not. It should just dispatch a "message", and move on.
I am thinking to use a multiprocessing.Pool for this task and "dispatch the messages" with apply_async. Usually one would use get() to get the result, but in my case that would complicate the code slightly. So I am thinking of never actually calling get(). Is that legal, or is this going to cause a cache (with None returns) somewhere to blow up after a while?
Just discovered Node.io, gone though the docs, api, etc. and it looks great. However, building my first job exports.job = new nodeio.Job(..), with methods like input, run,output, reduce, complete I'm in need of some kind of initialize() method which is called once, before successive calls to input() are done. (Similar how complete is called once just before the job is finished)
Any such method around?
For completeness:
This code imho has to be part of the node.io flow (through some dedicated method) since initializing my async code outside of the node.io scope doesn't guarentee the data is already there before the node.io job is executed.
I don't know if there is such a method, have you browsed through the source? It looks like there is an 'init' method that is called by the processor if it is on the job. If you try that and it isn't what you're looking for, you could suggest this as a feature on the node.io github site.
Otherwise, this would be a very simple thing to add for yourself. Just add an 'initialize' method to your object, and then put the following lines at the top of your 'input' or 'run' method (which I think would probably work better if you need the data to be ready already):
if (!this.initialized) {
this.initialized = true;
this.initialize();
}
Note that there is a tiny performance hit here, of course. But in most cases, it's only the amount of time it takes to check the value of one variable, which is probably quite minimal compared to the amount of processing you actually need.
I know that flex does not support multi threading however, I would like to clear a doubt.
I have two events that call a same function. Suppose the two events occur at the same instant (or in quick succession) will the handler be called twice, one after the other or there is a chance that if the handler function is taking too much time to execute the same handler can start executing simultaneously.
Thnanks
The handler will be called twice, once with each event. The second call (and essentially, the entire app) will be blocked until the first call has returned.
Here's a nice overview of the event cycle--doesn't specifically address your question, but it's a nice broad picture.
And you can't go wrong with the elastic racetrack.
Yes it will always get called twice. Yes one of the two calls will complete before the other is started. Unless you are doing something like dispatching an event in the handler for another handler to work on, then it all goes out the window! Even then I believe the first call will complete, but the event it dispatched may get resolved before the second call happens, sometimes....sorta. ;)
YMMV
If you didn't know, using PixelBender, Flex can do multi-threading. Other than for graphics, you can make use of pixelbender to do mathematical functions quickly which you may find a use for :)