4

A common pattern in typescript clients is to put multiple solana JSON RPC http calls promises into a Promise.all in order to reduce wait time.

How would one achieve the same with the solana_sdk::rpc_client::RpcClient, or even the solana_sdk::nonblocking::rpc_client::RpcClient? The goal being reaching a reasonably efficient solution

One example is the usual getMultipleAccountInfos chunking.

I have something that works but it feels clunky

let keys: Vec<Pubkey> = vec![...]; // many keys
for chunk in keys.chunks(100) {
    let chunk = chunk.iter().map(|c| **c).collect::<Vec<_>>();

    handles.push(async move {
        let accounts = rpc_client.get_multiple_accounts(&chunk).await.unwrap();
        zip(chunk, accounts)
    });
}
let zips = future::join_all(handles).await;

for zip in zips {
    for (key, account) in zip {
        match account {
            Some(account) => {
                // Do something here with the new data
            }
            None => println!("For some reason, couldn't find {}", key),
        }
    }
}
2
  • 2
    could you elaborate which part(s) you'd like to improve? it looks 90% of the way there to me
    – trent.sol
    Jul 28 at 4:13
  • It looked clunky to me but maybe this is the way.
    – Arowana
    Jul 29 at 3:24

1 Answer 1

1

Hope this helps ur method of join_all works concurrently not parallelism, in order to get the expected output u need to use a multithreaded runtime like tokio where you create seperat greenthreads/tasks and pass it to spawn , these tasks do not need to wait for block_on to execute them if your cores/worker threads are ready they will execute them in parallel if your tasks are independent then this is how you should do them, a excerpt i found which puts all this nice below. in your current form only one task at a time is being executed not multiple tasks being executed at once.

One alternative that might provide you a bit more parallelism is to use a multithreaded async runtime (e.g. tokio) and spawn each async function as a separate task. In that case the tasks could run on separate CPU cores and threads and wouldn't block each other that much. You can then use join_all on the collection of returned JoinHandles to wait for all tasks to complete.

4
  • So the advantage parallelism would bring is that decoding would occur on multiple thread while concurrency would be enough if there was none as most of the job would be IO. Is that correct?
    – Arowana
    Aug 2 at 12:30
  • kinda yes, not sure if we can assume that concurrency in your context would be fast enough that it would give almost the same benchmarks as doing in parallel for instance instead of simply pushing futures and concurrently awaiting them, you could spawn, several tasks and use join_all on the returned join handles atmost it should give you better performance, as for the decoding part, asynchronous programming does not help with cpu intensive tasks , atmost using the async keyword would provide no performance disadvantage but no advantage either, in your case while decoding there is no I/O 1/2 Aug 3 at 1:10
  • 2/2 Also do checkout the runtime you use, usually tokio runtime spawns some x number of OS threads , spawning async tasks wont help with decoding it would be reading from in-memory right ? its not like you are reading from a file or another blocking input source, what you can try is iterate over the accounts and spawn threads and decode in each separate thread but doing this manually is highly inefficient, check out the rayon crate which is really simple and provides you a par_iter effectivly executing your tasks in parallel utilizing work-stealing etc Aug 3 at 1:15
  • In short use a parallel asynchronous runtime to get multiple accounts in memory and proceed to use rayon to decode them in parallel. Aug 3 at 1:18

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.