yageek
yageek

Reputation: 4455

Alternative to cloning tokio channel's sender for futures' closures

I'm working with tokio and hyper to spawn several tasks.

// Defining the task
let task = self.some_future_using
            .map(move |resp| println!("OK: {}", resp))
            .map_err(move |e| println!("Error: {}",e));

// Spawning the task
tokio::spawn(task);

Instead of simply logging the results, I would like to send the result over a bounded tokio channel.

// Defines the channel
let (tx, rx) = mpsc::channel(10);

// Defining the task
let task = self.some_future_using
            .map(|resp| /* Send Ok(resp) to tx */ )
            .map_err(|e| /* Send Err(e) to tx */);

// Spawning the task
tokio::spawn(task);

As both closures may outlive the scope where tx is defined, we need to clone and move tx for both closures:

// Defines the channel
let (tx, rx) = mpsc::channel(10);
let mut tx_ok = tx.clone();
let mut tx_err = tx.clone();

// Defining the task
let task = self.some_future_using
            .map(move |resp| tx_ok.try_send(Ok(())).unwrap() )
            .map_err(move |e| tx_err.try_send(Ok(())).unwrap() );

// Spawning the task
tokio::spawn(task);

In the case more logic is added using combinators (map, and_then, etc), every closures would require it's own cloned version of tx to use it.

Is cloning the only solution? Could we achieve the same without cloning the channel's sender for each declared closure that uses it?

Upvotes: 1

Views: 1605

Answers (1)

Peter Hall
Peter Hall

Reputation: 58735

Could we achieve the same without cloning the channel's sender for each declared closure that uses it?

No. This is how a Sender is shared, and there isn't another safe way to do it.

The channel manages shared resources by wrapping them in Arcs, so they can be shared safely between threads. There is a bit of logic involved in the Sender's clone method, but ultimately it is about cloning those Arcs - which is how Arcs are shared.

Cloning an Arc is cheap, and probably not something you should worry about, unless you are cloning them in a tight loop. Once they are cloned, there is very little overhead to an Arc - each clone is essentially a pointer.

Upvotes: 2

Related Questions