Skip to content

Resource

Shared resource with limited capacity.

Resource

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

simulation environment.

required
capacity int

maximum capacity.

1

Raises:

Type Description
ValueError

for invalid capacity.

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
34
35
36
37
38
39
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