Overview
In this guide, you can learn how to optimize the performance of the
Rust driver. To connect to MongoDB, you must create a Client instance.
Your Client instance automatically handles most aspects of connection, such
as discovering server topology and monitoring your connection. This guide
describes best practices for configuring and using your Client instance.
This guide includes the following sections:
Client Lifecycle describes best practices for creating and managing a
Clientinstance.Parallelism provides sample code for running parallel, asynchronous tasks.
Runtime describes how to manage runtimes by using functionalities of the
tokioandasync_stdcrates.Additional Information provides links to resources and API documentation for types and methods mentioned in this guide.
Tip
You can optimize performance by using connection pools. To learn more, see the Manage Connections with Connection Pools guide.
Client Lifecycle
We recommend that you reuse your client across sessions and operations.
You can use the same Client instance to perform multiple tasks, as
the Client type is safe for concurrent use by multiple threads.
Creating a new Client instance for each request results in slower
performance.
The following code creates a method that accepts a pointer to an
existing Client instance, which allows you to perform many requests
by using the same client:
// ... Create a client earlier in your code async fn make_request(client: &Client) -> Result<(), Box<dyn Error>> { // Use the client to perform operations Ok(()) }
Parallelism
You can optimize performance by running asynchronous, concurrent tasks
to execute parallel data operations. The following example uses the
spawn() method from the tokio::task module to create separate,
concurrent tasks to perform insert operations:
let client = Client::with_uri_str("<connection string>").await?; let data = doc! { "title": "1984", "author": "George Orwell" }; for i in 0..5 { let client_ref = client.clone(); let data_ref = data.clone(); task::spawn(async move { let collection = client_ref .database("items") .collection::<Document>(&format!("coll{}", i)); collection.insert_one(data_ref).await }); }
Runtime
A Client instance is bound to the instance of the tokio or
async-std runtime in which you created it. If you use a Client
instance to perform operations on a different runtime, you might
experience unexpected behavior or failures.
If you use the test helper macro from the tokio or
async_std crate to test your application, you might unintentionally run
operations on a different runtime than the Client instance expects. This occurs because these
helper macros create a new runtime for each test. You can use
one of the following strategies to avoid this issue:
Attach the runtime to the
Clientinstance without using thetesthelper macros.Create a new
Clientinstance for everyasynctest.
The following example attaches a global runtime to a Client instance for testing.
The test_list_dbs() method uses a client that
connects to this runtime to list databases in the deployment:
use tokio::runtime::Runtime; use once_cell::sync::Lazy; static CLIENT_RUNTIME: Lazy<(Client, Runtime)> = Lazy::new(|| { let rt = Runtime::new().unwrap(); let client = rt.block_on(async { Client::with_uri_str("<connection string>").await.unwrap() }); (client, rt) }); fn test_list_dbs() -> Result<(), Box<dyn Error>> { let (client, rt) = &*CLIENT_RUNTIME; rt.block_on(async { client.list_database_names().await })?; Ok(()) }
The following example creates a new Client instance for each test
run with tokio::test, ensuring that there are no unintended
interactions between runtimes:
async fn test_list_dbs() -> Result<(), Box<dyn Error>> { let client = Client::with_uri_str("<connection string>").await?; client.list_database_names().await?; Ok(()) }
Additional Information
To learn more about connecting to MongoDB, see the Create a MongoDB Client guide.
To learn more about the available runtimes for the Rust driver, see the Asynchronous and Synchronous APIs guide.
To learn how to optimize performance by using connection pools, see the Manage Connections with Connection Pools guide.
API Documentation
spawn() in the
tokio::taskmoduletokio::runtime module