sharded-slab icon indicating copy to clipboard operation
sharded-slab copied to clipboard

Provide `Entry` that can cross the `.await` point

Open loyd opened this issue 1 year ago • 1 comments

Now Entry: !Send; thus, it cannot cross the .await point in multithreaded runtimes like tokio.

I don't see anything in the code that relies on these restrictions, so the main question here is whether Entry can be an instance of Send or not. If not, can you recommend something for the case below?

Use case

I use the sharded-slab as actor storage in elfo, and it has been working fine for years in production, so thanks for the crate. The next version will use cordyceps as part of the mailbox implementation, so thanks for that implementation, too.

In the simplest case, when some actor wants to send a message to another one with a known address and wants async backpressure, it gets a target actor by its address in the slab. In the simplified form, it looks like the following code:

async fn send_to<M: Message>(&self, recipient: usize, message: M) -> Result<(), SendError<M>> {
    let Some(actor) = self.slab.get_owned(recipient) else {
        return Err(SendError(message)
    };
    actor.mailbox.send(message).await
}

The problem is that get_owned clones Arc every time, creating a massive contention on the counter that kills performance on multicore (especially on NUMA) machines. The implementation for sync try_send_to (uses slab.get() inside) doesn't have a similar behavior.

I use get_owned here instead of get only because Entry cannot cross the .await point. Logically, the future cannot overlive the slab.

loyd avatar Feb 25 '24 00:02 loyd

I think the Entry type can probably be Send. Off the top of my head, I certainly can't think of any reason why it can't be.

hawkw avatar Feb 26 '24 03:02 hawkw