Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Semaphore doc final cleanup #6050

Merged
merged 5 commits into from Oct 5, 2023
Merged
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
44 changes: 28 additions & 16 deletions tokio/src/sync/semaphore.rs
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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 {
Expand All @@ -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.
Expand All @@ -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.
Expand All @@ -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.
Expand All @@ -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;
Expand All @@ -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.
Expand All @@ -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;
Expand Down Expand Up @@ -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 `Permit::forget` method.
Darksonn marked this conversation as resolved.
Show resolved Hide resolved
/// permit.forget();
/// }
/// }
///
Expand Down