Search code examples
rustrust-tokio

Wait for senders to drop vs join! macro


At the bottom of the page on graceful shutdown in the Tokio docs it suggests a neat way to wait for tasks to finish using an mpsc channel and waiting for the channel to be closed, which happens when every sender has been dropped.

What are the advantages this offers over just tokio::join! on the tasks you're expecting to finish? The channels method does mean you can avoid creating handles to all your tasks, if you don't otherwise care about the results coming out. But it isn't clear it makes the code easier to read with the additional drop(tx), and you're required to pass an extra _sender: Sender<()> parameter into each task.

Does it just boil down to style or is there another reason to favour channels here?


Solution

  • The advantage which I see to the channel approach is that it is more composable; it is easier to distribute through some complex system.

    In their example — "spawn 10 tasks, then use an mpsc channel to wait for them to shut down" — the ten tasks are right there. But what if some tasks are spawned dynamically, later, or "privately" within some subsystem?

    All of these can be handled by passing the sender clones down to all the parts. The receiver holder need not know what all those parts are.

    and you're required to pass an extra _sender: Sender<()> parameter into each task.

    Note that, in a more complex situation than an example, the sender could be carried within some context object that the tasks need anyway. The sender also does not have to be cloned itself; an Arc containing some context struct containing the sender will do just as well.