diff --git a/tokio/src/sync/semaphore.rs b/tokio/src/sync/semaphore.rs index fb907b6b5..7a060075d 100644 --- a/tokio/src/sync/semaphore.rs +++ b/tokio/src/sync/semaphore.rs @@ -47,7 +47,7 @@ use std::sync::Arc; /// } /// ``` /// -/// ## Limit the number of simultaneously opened files in your program. +/// ## Limit the number of simultaneously opened files in your program /// /// Most operating systems have limits on the number of open file /// handles. Even in systems without explicit limits, resource constraints @@ -76,7 +76,7 @@ use std::sync::Arc; /// } /// ``` /// -/// ## Limit the number of incoming requests being handled at the same time. +/// ## Limit the number of incoming requests being handled at the same time /// /// Similar to limiting the number of simultaneously opened files, network handles /// are a limited resource. Allowing an unbounded amount of requests to be processed @@ -125,19 +125,23 @@ use std::sync::Arc; /// /// ## Prevent tests from running in parallel /// -/// By default, Rust runs tests in the same file in parallel. However, in some cases, running two tests in parallel may lead to problems. -/// For example, this can happen when tests use the same database. +/// By default, Rust runs tests in the same file in parallel. However, in some +/// cases, running two tests in parallel may lead to problems. For example, this +/// can happen when tests use the same database. /// /// Consider the following scenario: -/// 1. `test_insert`: Inserts a key-value pair into the database, then retrieves the value using the same key to verify the insertion. -/// 2. `test_update`: Inserts a key, then updates the key to a new value and verifies that the value has been accurately updated. -/// 3. `test_others`: A third test that doesn't modify the database state. It can run in parallel with the other tests. +/// 1. `test_insert`: Inserts a key-value pair into the database, then retrieves +/// the value using the same key to verify the insertion. +/// 2. `test_update`: Inserts a key, then updates the key to a new value and +/// verifies that the value has been accurately updated. +/// 3. `test_others`: A third test that doesn't modify the database state. It +/// can run in parallel with the other tests. /// -/// In this example, `test_insert` and `test_update` need to run in sequence to work, but it doesn't matter which test runs first. -/// We can leverage a semaphore with a single permit to address this challenge. +/// In this example, `test_insert` and `test_update` need to run in sequence to +/// work, but it doesn't matter which test runs first. We can leverage a +/// semaphore with a single permit to address this challenge. /// /// ``` -/// use tokio::sync::Semaphore; /// # use tokio::sync::Mutex; /// # use std::collections::BTreeMap; /// # struct Database { @@ -164,6 +168,7 @@ use std::sync::Arc; /// # *self.map.lock().await.get(key).unwrap() /// # } /// # } +/// use tokio::sync::Semaphore; /// /// // Initialize a static semaphore with only one permit, which is used to /// // prevent test_insert and test_update from running in parallel. @@ -173,7 +178,7 @@ use std::sync::Arc; /// static DB: Database = Database::setup(); /// /// #[tokio::test] -/// # async fn fake_test() {} +/// # async fn fake_test_insert() {} /// async fn test_insert() { /// // Acquire permit before proceeding. Since the semaphore has only one permit, /// // the test will wait if the permit is already acquired by other tests. @@ -196,7 +201,7 @@ use std::sync::Arc; /// } /// /// #[tokio::test] -/// # async fn fake_test() {} +/// # async fn fake_test_update() {} /// async fn test_update() { /// // Acquire permit before proceeding. Since the semaphore has only one permit, /// // the test will wait if the permit is already acquired by other tests. @@ -221,12 +226,12 @@ use std::sync::Arc; /// } /// /// #[tokio::test] -/// # async fn fake_test() {} +/// # async fn fake_test_others() {} /// async fn test_others() { /// // This test can run in parallel with test_insert and test_update, /// // so it does not use PERMIT. /// } -/// # #[tokio::main] +/// # #[tokio::main(flavor = "current_thread")] /// # async fn main() { /// # test_insert().await; /// # test_update().await; @@ -236,6 +241,8 @@ use std::sync::Arc; /// /// ## Rate limiting using a token bucket /// +/// This example showcases the [`add_permits`] and [`SemaphorePermit::forget`] methods. +/// /// Many applications and systems have constraints on the rate at which certain /// operations should occur. Exceeding this rate can result in suboptimal /// performance or even errors. @@ -256,6 +263,8 @@ use std::sync::Arc; /// lot of cpu constantly looping and sleeping. /// /// [token bucket]: https://en.wikipedia.org/wiki/Token_bucket +/// [`add_permits`]: crate::sync::Semaphore::add_permits +/// [`SemaphorePermit::forget`]: crate::sync::SemaphorePermit::forget /// ``` /// use std::sync::Arc; /// use tokio::sync::Semaphore; @@ -292,8 +301,11 @@ use std::sync::Arc; /// /// async fn acquire(&self) { /// // This can return an error if the semaphore is closed, but we -/// // never close it, so just ignore errors. -/// let _ = self.sem.acquire().await; +/// // never close it, so this error can never happen. +/// let permit = self.sem.acquire().await.unwrap(); +/// // To avoid releasing the permit back to the semaphore, we use +/// // the `SemaphorePermit::forget` method. +/// permit.forget(); /// } /// } ///