Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reverse stream / non-blocking control #12

Open
janismac opened this issue Sep 24, 2018 · 5 comments
Open

Reverse stream / non-blocking control #12

janismac opened this issue Sep 24, 2018 · 5 comments
Labels
enhancement New feature or request protocol

Comments

@janismac
Copy link

janismac commented Sep 24, 2018

I noticed that the this snippet is quite slow, it takes around 40ms.

t0 = time()
control.pitch = (...)
control.yaw = (...)
print('dt', time() - t0)

Is there a non-blocking interface for sending data, analogous to streams for receiving data?

EDIT: Or is there at least a way to batch the control updates into a single RPC?


Btw, a big thanks for making this mod! Have you considered opening a Patreon account for this project? I'd like to encourage future maintenance ;)

@djungelorm
Copy link
Member

There is already batching functionality in the server, but the clients don't yet expose it. Shouldn't be too hard to extend them to support this.

And thanks for the offer of Patreon support, but money isn't really an issue or motivator for me - more just the fun of programming and kerbal combined! Unfortunately time is the one thing I lack, and although I do have time to maintain the mod, finding time to add larger features has been lacking recently.

@BenChung
Copy link

My Julia client supports this, but I'm not happy with the API yet...

Also, seconded with being interested in Patreon, I, too, would like to support development :)

@janismac
Copy link
Author

janismac commented Oct 3, 2018

I thought about how to implement this RPC buffering/batching in the Python client library. @djungelorm maybe you can comment on whether this is a good idea.

This would only apply to setters, because with setters we don't need to worry about getting a return or result value back to the user.
I would replace the cls._client._invoke here and here with a variant of that function, maybe cls._client._invoke_buffered.

Client._invoke_buffered() would save the ProcedureCall in a buffer array and return immediately. Then a call to Client.send_updates() would send all the ProcedureCalls in a single Request and clear the array.

And a flag would be needed to switch between the old and new behavior, maybe Client.set_update_buffer_mode(True/False).

@djungelorm
Copy link
Member

Here are my thoughts:

  • I think this should apply to more than just setters. In general, any RPC call could have side effects, and in some parts of the API a method call is used to set something, rather than just a setter. This includes getters and method, which brings me to point 2:
  • Getters and methods that return values could conceivable be passed out when invoking the batch - and I can envisage this being useful. For example, if you wanted to get a few flight parameters once with lowest latency possible (setting up several streams or calling the RPCs one after the other would be lower latency)

Your send_updates approach seems clean, but one issue I have with it is that it requires the set_update_buffer_mode. I think this would make client code hard to debug, as it's not obvious what "mode" the client is in by just looking at the code. An alternative approach that wouldn't need this would be to have some sort of Batch object that you can add RPCs to, and then call. For example:

batch = client.create_batch()
batch.add(getattr, flight, 'vertical_speed')
batch.add(...)
batch.add(...)
batch.invoke()

(batch.add is using the same syntax as creating a stream with client.stream(...))

This would have the added benefits of:

  • Allowing you to invoke a batch multiple times without recreating it.
  • Allowing you to intervleave "normal" RPCs in between the calls to set up the batch.
  • Abandoning a batch half way through it's construction by just discarding the object

@BenChung
Copy link

BenChung commented Oct 8, 2018

The way I've implemented this functionality in Julia is to add a separate namespace for what I refer to as delayed RPC calls. For example,

 kRPC.Remote.SpaceCenter.Velocity(flight)

will immediately make an RPC call to find the velocity, whereas

 kRPC.Remote.SpaceCenter.Delayed.Velocity(flight)

will return a ProcedureCall that can get passed into a later call to SendMessage that returns the result. This allows the construction and modification of batches as simple arrays. Return values come back in the order of the passed procedure calls. The main issue that I have with it is that it's pretty messy and duplicates all of the calls, which is a substantial problem in the Julia context (where having two methods with the same signature and name is a real problem).

@djungelorm djungelorm added enhancement New feature or request protocol labels Mar 9, 2023
@djungelorm djungelorm mentioned this issue Mar 26, 2023
10 tasks
@djungelorm djungelorm transferred this issue from krpc/krpc Mar 26, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request protocol
Projects
None yet
Development

No branches or pull requests

3 participants