A shared resource with limited capacity.
Source code in src/asimpy/resource.py
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76 | class Resource:
"""A shared resource with limited capacity."""
def __init__(self, env: "Environment", capacity: int = 1):
"""
Construct resource.
Args:
env: simulation environment.
capacity: maximum capacity.
Raises:
ValueError: for invalid `capacity`.
"""
if capacity <= 0:
raise ValueError(f"resource capacity must be positive, got {capacity}")
self._env = env
self.capacity = capacity
self._count = 0
# deque gives O(1) popleft instead of O(n) list.pop(0).
self._waiters: deque = deque()
async def acquire(self):
"""Acquire one unit of resource."""
if self._count < self.capacity:
await self._acquire_available()
else:
await self._acquire_unavailable()
def release(self):
"""Release one unit of resource."""
self._count -= 1
# Lazy deletion: skip waiters that were cancelled while queued.
while self._waiters:
evt = self._waiters[0]
if evt._value is _CANCELLED:
self._waiters.popleft()
continue
self._waiters.popleft()
evt.succeed()
self._count += 1
break
async def _acquire_available(self):
self._count += 1
evt = Event(self._env)
# Pre-trigger so the tight loop in Process._loop resumes without
# going through the heap. The event is already triggered, so
# cancellation is a no-op and _on_cancel is not needed.
evt.succeed()
await evt
async def _acquire_unavailable(self):
evt = Event(self._env)
# No _on_cancel: lazy deletion in release() handles cancelled entries.
self._waiters.append(evt)
await evt
self._count += 1
async def __aenter__(self):
await self.acquire()
return self
async def __aexit__(self, exc_type, exc, tb):
self.release()
|
__init__(env, capacity=1)
Construct resource.
Parameters:
| Name |
Type |
Description |
Default |
env
|
Environment
|
|
required
|
capacity
|
int
|
|
1
|
Raises:
| Type |
Description |
ValueError
|
|
Source code in src/asimpy/resource.py
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32 | def __init__(self, env: "Environment", capacity: int = 1):
"""
Construct resource.
Args:
env: simulation environment.
capacity: maximum capacity.
Raises:
ValueError: for invalid `capacity`.
"""
if capacity <= 0:
raise ValueError(f"resource capacity must be positive, got {capacity}")
self._env = env
self.capacity = capacity
self._count = 0
# deque gives O(1) popleft instead of O(n) list.pop(0).
self._waiters: deque = deque()
|
acquire()
async
Acquire one unit of resource.
Source code in src/asimpy/resource.py
| async def acquire(self):
"""Acquire one unit of resource."""
if self._count < self.capacity:
await self._acquire_available()
else:
await self._acquire_unavailable()
|
release()
Release one unit of resource.
Source code in src/asimpy/resource.py
41
42
43
44
45
46
47
48
49
50
51
52
53 | def release(self):
"""Release one unit of resource."""
self._count -= 1
# Lazy deletion: skip waiters that were cancelled while queued.
while self._waiters:
evt = self._waiters[0]
if evt._value is _CANCELLED:
self._waiters.popleft()
continue
self._waiters.popleft()
evt.succeed()
self._count += 1
break
|