sync: Semaphore doc final cleanup (#6050)

This commit is contained in:
Alice Ryhl 2023-10-05 14:43:49 +02:00 committed by GitHub
parent 5d29136a83
commit d6ed00c292
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

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