
Stjepan Rajko wrote:
On 4/29/07, Jeff Garland <jeff@crystalclearsoftware.com> wrote:
Stjepan Rajko wrote:
I can see that as being reasonable if the RPC is synchronous, but if Well, not necessarily.
Are you referring to the possibility that the parameter might not be specified as an out parameter, or do you have something else in mind? No, my general point really is that the whole idea of 'making an RPC appear like a local function call' is dangerous in my view. There are just too many differences between remote calls and local calls that the programmer ultimately needs to know about. For example, how does the rpc endpoint addressed, what if the endpoint refuses connection, and (specifically related to synchronous behavior) how long is my process blocked while waiting for a response that may never come or may be delayed for several seconds because it takes 3 satellite hops before the result returns? When you make a function call in a normal program you don't think about any of these factors. When you make an RPC, you should be thinking about these things. Similarly, network access is fundamentally asynchronous, so why not program it that way?
I think that there are circumstances in which adopting the simplicity of simulating a local function is worthwhile (you mentioned some in your previous message, e.g. function calls which are quickly evaluated, especially if the network is just a few computers sitting
But you've already fallen into the trap. Just because the computers are next to each other doesn't mean you are going to get an immediate answer. For example, one of the computers you are communicating with might be really busy doing something (swapping perhaps if it's overloaded). It might be so busy the process you are communicating with can't service it's TCP queue. Data starts stacking up in the queue of the OS. The network is fine, no errors are happening, but your simple 'doit' function is now blocked for minutes. It's completely unexpected. In the meantime your application appears to be 'hung' -- it's waiting for a response that isn't coming and instead of 1 machine behaving badly it looks like there's 2. Ok, so you're a smart guy, and now you provide a timeout option on the RPC function so that when it's called you know it will return within 5 seconds (of course you actually expect a response in milliseconds) if there's no response. Great, but now you've blown the cover on this 'synchronous call' because a timeout and timeout error isn't something required on a normal function call. And at this point, is it really that much harder to make an async call and wait for either a timeout or a response? Basically, I'm pushing that programmers should start thinking of async first and sync second because you're going to wind up there most of the time anyway. The sync approach is so inherently limited that it's almost always flawed to use it.
next to each other connected over a local switch), and like you point out, there are circumstances in which ignoring the reality of network communication can be both dangerous and wasteful. FWIW, I think both approaches should be supported, as long as the behavior of the RPC is well designed and documented for both the sync case and the async case.
Well, the worry is that folks tend to gravitate toward the apparently simple solution in contexts where it doesn't work and then get surprised later when these considerations that 'weren't obvious' start cropping up. So most of the time I'd prefer to encourage people to think about the design of what they are doing.
Great thoughts... Along the lines of a thread pool, asio does provide the facility that would allow me to give it multiple threads as working threads, and it's behavior would I think match the one you describe - a received packet would go to an idle thread, which would then stay busy until the call was completed and returned. Perhaps I can try going this route. Which facility is that exactly?
Documentation of void boost::asio::io_service::run():
"Run the io_service's event processing loop.
The run() function blocks until all work has finished and there are no more handlers to be dispatched, or until the io_service has been interrupted.
Multiple threads may call the run() function to set up a pool of threads from which the io_service may execute handlers. ... "
In addition, an io_service can have a permanent work attached to it which will keep the event processing loop active even if all of the real communication events have been processed.
Does that sound like it would work to accomplish what you suggested? I haven't tried it yet.
I'm not 100% sure, I haven't tried that feature of asio. My guess is that it's a little different in that there may be a relationship between the io requests posted in the thread and where the callbacks are processed....so you have to 'know in advance' how threads and processing map. That's different from a typical thread pool. Anyway, one of us will either need to try it or ask Chris :-) Jeff