pycapnp icon indicating copy to clipboard operation
pycapnp copied to clipboard

RPC throughput slow due to poll sleep

Open LasseBlaauwbroek opened this issue 3 years ago • 3 comments

pycapnp is based on polling and generally sleeps for 0.01 second between polls. This means that a maximum of 100 messages per second can be exchanged. This is a significant slow-down. By decreasing the sleeping time, I can get a throughput in the order of 10000 messages per second. So at least I would suggest decreasing the sleeping time. But this comes at the cost of higher idle cpu.

Is there any way of using the library in a blocking style without relying on polling?

LasseBlaauwbroek avatar May 03 '21 17:05 LasseBlaauwbroek

Yeah, I agree this is a problem.

The tricky part is that two async systems (kj and asyncio) have to talk to each other. I believe this is possible but I haven't been able to figure out a better way (so far). Effectively asyncio needs a way to be told "an event happened, process it".

haata avatar May 03 '21 18:05 haata

KJ's event loop APIs are designed to be able to stack on top of other event loops. It's not easy, but it's possible. I did it for Node.js's libuv here (first 654 lines of the file): https://github.com/capnproto/node-capnp/blob/node10/src/node-capnp/capnp.cc

kentonv avatar May 03 '21 18:05 kentonv

I'd love to resolve this issue somehow. Can either of you suggest a reasonable way of performing the stacking of the event loops? I'm having trouble matching the implementation @kentonv did for node.js and how that would transfer to pycapnp.

LasseBlaauwbroek avatar Oct 04 '21 15:10 LasseBlaauwbroek

I stumbled upon this issue when checking why an async application based on pycapnp results in about 5-10% persistent CPU usage on a Raspberry Pi. Although the former is no deal-breaker for us, the performance implications resulting from the polling mechanism definitely are.

I am not familiar with the implementation details of Cap'nProto and KJ, but would it be an option to address this issue by doing a synchronous wait in another thread and handing the data via an awaitable pipe or queue to the main thread? (I also thought about an asyncio.Future triggered via loop.call_soon_threadsafe, but this would probably require spawning a new thread for each read and a_wait invocation.)

felix-walter avatar Nov 08 '22 10:11 felix-walter

I haven't dug too deep into this, but this might provide some hints https://stackoverflow.com/questions/51029111/python-how-to-implement-a-c-function-as-awaitable-coroutine and https://stackoverflow.com/a/54675255

The main thing is to give enough to the python asyncio api such that we don't need to poll.

haata avatar Nov 14 '22 19:11 haata