Reputation: 4455
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
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 Arc
s, 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 Arc
s - which is how Arc
s 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