简体   繁体   中英

How to use RpcClient in multiple threads

I'm writing a program that prints out your SOL balance in the terminal but shows a loading indicator while fetching it. I am using the RpcClient from the solana_client crate to get my SOL balance but on a new thread, so I can spin the loading indicator on the main thread while the request is running.

My issue is that I get an error if I try to use the RpcClient's pointer in the function that I pass in to thread::spawn() :

fn main() {
    let url = "https://api.testnet.solana.com".to_string();
    let client = RpcClient::new(url);
    let pubkey = Pubkey::from_str(ADDRESS).unwrap();

    get_balance(&client, &pubkey);
}

fn get_balance(client: &RpcClient, pubkey: &Pubkey) {
    let (tx, rx): (Sender<u64>, Receiver<u64>) = mpsc::channel();
    let pubkey = pubkey.clone();
    thread::spawn(move || {
        let balance = client.get_balance(&pubkey).unwrap();
        tx.send(balance)
            .expect("failed to send back result throught tx channel");
    });
    let balance = spin(rx);
    println!("balance: {}", balance);
}

The error:

error[E0759]: `client` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
   --> src/main.rs:24:19
    |
21  |   fn get_balance(client: &RpcClient, pubkey: &Pubkey) {
    |                          ---------- this data with an anonymous lifetime `'_`...
...
24  |       thread::spawn(move || {
    |  ___________________^
25  | |         let balance = client.get_balance(&pubkey).unwrap();
26  | |         tx.send(balance)
27  | |             .expect("failed to send back result throught tx channel");
28  | |     });
    | |_____^ ...is used here...
    |

I tried to make the client variable static but that results in another error:

...
    let client: &'static RpcClient = &RpcClient::new(url);
...
fn get_balance(client: &'static RpcClient, pubkey: &Pubkey) {
...

error[E0716]: temporary value dropped while borrowed
  --> src/main.rs:15:39
   |
15 |     let client: &'static RpcClient = &RpcClient::new(url);
   |                 ------------------    ^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
   |                 |
   |                 type annotation requires that borrow lasts for `'static`
...
19 | }
   | - temporary value is freed at the end of this statement

And I get the same error if I try to clone client inside get_balance function, like I did with pubkey .

I could solve this by passing in the url and creating a new RpcClient inside the thread, but I'm trying to understand why my current implementation doesn't work, and how I should approach this type of issue when working with threads.

Thanks to Caesar's comment I was able to solve the problem by wrapping the client in an Arc :

fn main() {
    let url = "https://api.testnet.solana.com".to_string();
    let client = Arc::new(RpcClient::new(url));
    let pubkey = Pubkey::from_str(ADDRESS).unwrap();
    get_balance(&client, &pubkey);
}

fn get_balance(client: &Arc<RpcClient>, pubkey: &Pubkey) {
    let (tx, rx): (Sender<u64>, Receiver<u64>) = mpsc::channel();
    let client = client.clone();
    let pubkey = pubkey.clone();
    thread::spawn(move || {
        let balance = client.get_balance(&pubkey).unwrap();
        tx.send(balance)
            .expect("failed to send back result throught tx channel");
    });
    let balance = spin(rx);
    println!("balance: {}", balance);
}

I also found a related post where the answer helped me understand why my original code wasn't working.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM