Skip to content

Commit f0054be

Browse files
committed
Tutorial: Impove section on Lock primitive.
1 parent c79fb00 commit f0054be

File tree

1 file changed

+26
-18
lines changed

1 file changed

+26
-18
lines changed

v3/docs/TUTORIAL.md

Lines changed: 26 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -627,17 +627,28 @@ This guarantees unique access to a shared resource. In the following code
627627
sample a `Lock` instance `lock` has been created and is passed to all tasks
628628
wishing to access the shared resource. Each task attempts to acquire the lock,
629629
pausing execution until it succeeds.
630+
```python
631+
from asyncio import Lock
632+
lock = Lock()
633+
```
634+
Synchronous methods:
635+
* `locked` No args. Returns `True` if locked.
636+
* `release` No args. Releases the lock. See note below.
637+
Asynchronous method:
638+
* `acquire` No args. Pauses until the lock has been acquired. Use by executing
639+
`await lock.acquire()`.
630640

641+
A task waiting on a lock may be cancelled or may be run subject to a timeout.
642+
The normal way to use a `Lock` is in a context manager:
631643
```python
632644
import asyncio
633645
from asyncio import Lock
634646

635647
async def task(i, lock):
636648
while 1:
637-
await lock.acquire()
638-
print("Acquired lock in task", i)
639-
await asyncio.sleep(0.5)
640-
lock.release()
649+
async with lock:
650+
print("Acquired lock in task", i)
651+
await asyncio.sleep(0.5)
641652

642653
async def main():
643654
lock = Lock() # The Lock instance
@@ -648,26 +659,24 @@ async def main():
648659

649660
asyncio.run(main()) # Run for 10s
650661
```
662+
Use of a context manager is strongly recommended - otherwise an application must
663+
ensure that `.release` is only ever called when that same task has called
664+
`.locked`. Calling `.release` on an unlocked `Lock` will raise a `ValueError`.
665+
Calling it on a `Lock` which has been locked by another task will cause that
666+
second task to produce a `ValueError` when it attempts to release the `Lock` or
667+
when its context manager exits. Context managers avoid these issues.
651668

652-
Methods:
653-
654-
* `locked` No args. Returns `True` if locked.
655-
* `release` No args. Releases the lock.
656-
* `acquire` No args. Coro which pauses until the lock has been acquired. Use
657-
by executing `await lock.acquire()`.
658-
659-
A task waiting on a lock may be cancelled or may be run subject to a timeout.
660-
The normal way to use a `Lock` is in a context manager:
661-
669+
For the brave the following illustrates use without a CM.
662670
```python
663671
import asyncio
664672
from asyncio import Lock
665673

666674
async def task(i, lock):
667675
while 1:
668-
async with lock:
669-
print("Acquired lock in task", i)
670-
await asyncio.sleep(0.5)
676+
await lock.acquire()
677+
print("Acquired lock in task", i)
678+
await asyncio.sleep(0.5)
679+
lock.release()
671680

672681
async def main():
673682
lock = Lock() # The Lock instance
@@ -678,7 +687,6 @@ async def main():
678687

679688
asyncio.run(main()) # Run for 10s
680689
```
681-
682690
###### [Contents](./TUTORIAL.md#contents)
683691

684692
## 3.2 Event

0 commit comments

Comments
 (0)