Re: Return value from CallMethod, default callback
That's one way to do it. You can do one better( without threading, that is ) like this, though: def call( method, request ): class callbackClass( object ): def __init__( self ): self.response = None def __call__( self, response ): self.response = response controller = Controller() callback = callbackClass() method( controller, request, callback ) return callback.response In this case, we're only using one thread and hiding the control flow inside a class that behaves like a function, where we can retrieve the return value later and actually return it. alan On Jan 8, 2:46 am, Pavel Shramov shra...@mexmat.net wrote: On Wed, Jan 07, 2009 at 06:23:31PM -0800, Alan Kligman wrote: I poked around a bit and the code above isn't correct (for a couple of reasons). But the question remains: should stubs be generated that return the response down the callstack instead of passing it through a callback function? You may use simple wrapper around RpcChannel object (see attachment) so all calls are synchronous and behave just like any other python function. Pavel sync.py 1KViewDownload --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups Protocol Buffers group. To post to this group, send email to protobuf@googlegroups.com To unsubscribe from this group, send email to protobuf+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/protobuf?hl=en -~--~~~~--~~--~--~---
Re: Return value from CallMethod, default callback
That's right. This will only work in code that runs synchronously. If your program is written to be asynchronous then you will need to pass a callback, so you wouldn't use this at all. That's why I brought this up in the first place. If the channel can tell, based on the callback it receives, where to pass the return value, then that is more useful and safe. On Jan 8, 3:48 pm, Pavel Shramov shra...@mexmat.net wrote: On Thu, Jan 08, 2009 at 10:00:35AM -0800, Alan Kligman wrote: That's one way to do it. You can do one better( without threading, that is ) like this, though: It's not better but 'looks more simple'. From threading only Condition is used which is very cheap compared to network interaction. Your code only works for synchronous cases. My first variants looks like Yours. def call( method, request ): class callbackClass( object ): def __init__( self ): self.response = None def __call__( self, response ): self.response = response controller = Controller() callback = callbackClass() method( controller, request, callback ) return callback.response In this case, we're only using one thread and hiding the control flow inside a class that behaves like a function, where we can retrieve the return value later and actually return it. So You must every time check that channel implementation is synchronous. And code became unportable to async channels. Pavel --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups Protocol Buffers group. To post to this group, send email to protobuf@googlegroups.com To unsubscribe from this group, send email to protobuf+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/protobuf?hl=en -~--~~~~--~~--~--~---
Re: Return value from CallMethod, default callback
I believe there was a proposal internally that if the caller passes None for the callback, the RPC implementation should block until completion and then return the result. Does that seem like what you want? On Wed, Jan 7, 2009 at 6:23 PM, Alan Kligman alan.klig...@gmail.com wrote: I poked around a bit and the code above isn't correct (for a couple of reasons). But the question remains: should stubs be generated that return the response down the callstack instead of passing it through a callback function? On Jan 7, 5:59 pm, Alan Kligman alan.klig...@gmail.com wrote: Does it make sense to change stub.rpc_channel.CallMethod( method_descriptor, rpc_controller, request, method_descriptor.output_type._concrete_class, callback) to return stub.rpc_channel.CallMethod( method_descriptor, rpc_controller, request, method_descriptor.output_type._concrete_class, callback=lambda x:None) in python/google/protobuf/service_reflection.py? If, for example, I'm running in a single thread and my underlying channel is blocking, it's strange to pass a callback in when control would normally return to the calling method after CallMethod has completed synchronously. Thoughts? a --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups Protocol Buffers group. To post to this group, send email to protobuf@googlegroups.com To unsubscribe from this group, send email to protobuf+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/protobuf?hl=en -~--~~~~--~~--~--~---
Re: Return value from CallMethod, default callback
Sounds fine to me, but it's up to Petar (cc'd). On Wed, Jan 7, 2009 at 7:04 PM, Alan Kligman alan.klig...@gmail.com wrote: Ya, that's exactly what I'm experimenting with now and precisely what I'm looking for. Would be perfect if the callback had a default value of None too. a On Jan 7, 10:02 pm, Kenton Varda ken...@google.com wrote: I believe there was a proposal internally that if the caller passes None for the callback, the RPC implementation should block until completion and then return the result. Does that seem like what you want? On Wed, Jan 7, 2009 at 6:23 PM, Alan Kligman alan.klig...@gmail.com wrote: I poked around a bit and the code above isn't correct (for a couple of reasons). But the question remains: should stubs be generated that return the response down the callstack instead of passing it through a callback function? On Jan 7, 5:59 pm, Alan Kligman alan.klig...@gmail.com wrote: Does it make sense to change stub.rpc_channel.CallMethod( method_descriptor, rpc_controller, request, method_descriptor.output_type._concrete_class, callback) to return stub.rpc_channel.CallMethod( method_descriptor, rpc_controller, request, method_descriptor.output_type._concrete_class, callback=lambda x:None) in python/google/protobuf/service_reflection.py? If, for example, I'm running in a single thread and my underlying channel is blocking, it's strange to pass a callback in when control would normally return to the calling method after CallMethod has completed synchronously. Thoughts? a --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups Protocol Buffers group. To post to this group, send email to protobuf@googlegroups.com To unsubscribe from this group, send email to protobuf+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/protobuf?hl=en -~--~~~~--~~--~--~---
Re: Return value from CallMethod, default callback
On Wed, Jan 07, 2009 at 06:23:31PM -0800, Alan Kligman wrote: I poked around a bit and the code above isn't correct (for a couple of reasons). But the question remains: should stubs be generated that return the response down the callstack instead of passing it through a callback function? You may use simple wrapper around RpcChannel object (see attachment) so all calls are synchronous and behave just like any other python function. Pavel --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups Protocol Buffers group. To post to this group, send email to protobuf@googlegroups.com To unsubscribe from this group, send email to protobuf+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/protobuf?hl=en -~--~~~~--~~--~--~--- #!/usr/bin/env python # vim: sts=4 sw=4 et import threading class _sync_cb: Synchronization callback def __init__(self): self.c = threading.Condition() def __call__(self, x): self.c.acquire() self.r = x self.c.notify() self.c.release() def rpc_sync(method): Make method synchronous by providing synchronization callback def nm(*args): cb = _sync_cb() method(*(args + (cb,))) cb.c.acquire() while not hasattr(cb, 'r'): cb.c.wait() cb.c.release() return cb.r return nm class RPCSync(object): Wrapper around RpcChannel object that changes default behaviour from asynchronous to synchronous. Controller class is provided once on wrapper creation so typical RPC call looks like. response = wrapper.method(request) On error RuntimeError exception containing ctrl.ErrorText() is raised def __init__(self, stub, ctrl_class): self.ctrl_class = ctrl_class self.stub = stub for m in self.stub.GetDescriptor().methods: self.__setattr__(m.name, self._func(m.name)) def _call(self, method, *args, **kwargs): ctrl = self.ctrl_class() result = rpc_sync(getattr(self.stub, method))(ctrl, *args, **kwargs) if ctrl.Failed(): raise RuntimeError(ctrl.ErrorText()) return result def _func(self, method): def f(*args, **kwargs): return self._call(method, *args, **kwargs) f.__name__ = method return f