Both messages are enqueued at send() and actually both sent at the first await. If destined at two different receivers, they can execute concurrently and, after the second await, will both have finished.
Motoko futures are eager, not lazy. Even if you donât await a future, its effects still happen.
@mraszyk might be able to answer about the Rust cdk. I believe it originally used eager semantics, but may since changed to lazy. Donât trust my answer.
I believe it originally used eager semantics, but may since changed to lazy.
Indeed, inter-canister calls in Rust (using ic_cdk::call) wonât be executed unless theyâre awaited (this is standard in Rust and the Rust compiler issues warnings if a future is not awaited). To execute multiple inter-canister calls in parallel in Rust, you can do the following:
let mut futs = vec![];
for i in 0..4 {
futs.push(call(my_favorite_canister, "foo", ((i),)));
}
let res: Vec<Result<(u64,), _>> = join_all(futs).await;
Thank you very much for this example! Iâm very excited to apply it to my work.
It seems in your example that you push to my_favorite_canister each time. Since this is the same canister, would it prevent the process from being parallelized? Would I have to call a distinct canister for each pushed call for it to be parallelized? Would queries be parallelizable to the same canister because it could go to a different node, but updates not? TIA
It seems in your example that you push to my_favorite_canister each time. Since this is the same canister, would it prevent the process from being parallelized? Would I have to call a distinct canister for each pushed call for it to be parallelized?
Indeed, calls to the same canister are executed sequentially by the IC. Hence, youâd need to call distinct canisters to benefit from concurrent execution of the calls. But you might already get some speed up when calling the same canister as I showed above since the calls will (very likely) be executed in a batch on the same thread without other canisters being executed on that thread in between.
Would queries be parallelizable to the same canister because it could go to a different node, but updates not?
No, to preserve the security guarantees of the IC, if you invoke a query method from an update call, then this query method is executed on all nodes just like an update call to an update method.
Thank you very much for the detailed response. This has all been very helpful and I am eager to integrate it into my code. I have one last question to help me understand the best course for my architecture.
Would using Composite_Query to invoke Queries require the same âsecurity guaranteeâ? Could a Composite Query have more than one Query concurrently executed by the same Canister on different nodes?
Would using Composite_Query to invoke Queries require the same âsecurity guaranteeâ?
No, the security guarantees of both query calls and composite query calls are weaker than the security guarantees of update calls since both query calls and composite query calls are executed by only one node.
Could a Composite Query have more than one Query concurrently executed by the same Canister on different nodes?
No, all individual queries executed as part of a composite query evaluation are evaluated on the same node that received the original composite query call.