usim.py.resources
– Synchronized Resources
μSim replicates all resource types provided by SimPy. Resources synchronize processes by sharing or exchanging objects, data, or ownership.
Resources with a fixed |
|
Resources with |
|
Resources with a fixed |
|
Common interface inherited by all resource types |
Just like the usim.py
, usim.py.resources
is a drop-in replacement
for simpy.resources
.
It is possible to use usim.py
resources both in usim.py
processes
as well as regular usim
activities.
μSim
async def block(resource: Resource):
with resource.get() as request:
await request
await (time + 5)
SimPy
def block(env, resource: Resource):
with resource.get() as request:
yield request
yield env.timeout(5)
Note
μSim only replicates the public, documented API of SimPy’s resources.
This includes private methods intended to be overridden, such as
_do_put()
.
Implementation details, especially of internal methods such as
_trigger_put()
,
may differ from SimPy.
Common Resource Interface
All resources of usim.py
derive from a common interface:
the BaseResource
with a given capacity,
and related events to
put
and
get
resource in or out of the resource.
- class usim.py.resources.base.BaseResource(env: usim.py.core.Environment, capacity)[source]
Base class for all synchronised resources of
usim.py
This type codifies the basic semantics of
usim.py
resources: processes canput()
content into the resource orget()
content out of the resource. Both actions return anEvent
; once the event triggers, the process did successfully get or put content into or out of the resource. Processes shouldyield
this even to wait for success of their request.def foo(env, resources: BaseResource): print('Getting a resource at', env.time) yield resources.get() print('Got resource at', env.time) yield env.timeout(2) print('Returning a resource at', env.time) yield resources.put() print('Returned a resource at', env.time)
Subclasses should define their behaviour by implementing at least one of:
PutQueue
orGetQueue
The types used to create the
put_queue
andget_queue
. These may, for example, customize priority of queued requests.put()
orget()
The methods used to create
Put
andGet
events. These may, for example, customize how much of a resource to handle at once._do_put()
or_do_get()
The methods used to process
Put
andGet
events. These are an alternative to customizingput()
orget()
.
Note
This is not an Abstract Base Class. Subclasses do not need to implement
_do_get()
or_do_put()
.Hint
Migrating to μSim
There is no common base type for resources in μSim – instead there are several different types of resources made for various use-cases. If you need to create a custom resource, you are free to choose whatever interface is appropriate for your use-case.
μSim itself usually uses the
await
,async for
andasync with
depending on the intended use of a resource. Commonly this meansawait resource
to get content from a resource,await resource.put(...)
to add content to a resource,async for item in resource:
to subscribe to a resource, andasync with resource:
to temporarily use a resource.- _do_put(get_event: usim.py.resources.base.Put) bool [source]
Trigger a
Put
event if possible- Parameters
get_event – the event that may be triggered
- Returns
whether another event may be triggered
- _do_get(get_event: usim.py.resources.base.Get) bool [source]
Trigger a
Get
event if possible- Parameters
get_event – the event that may be triggered
- Returns
whether another event may be triggered
- property capacity
Maximum capacity of the resource
- get() usim.py.resources.base.Get[usim.py.resources.base.T] [source]
Create a request to get content out of the resource
- get_queue
pending get events
- put() usim.py.resources.base.Put[usim.py.resources.base.T] [source]
Create a request to put content into the resource
- put_queue
pending put events
Each request to
put
or
get
resources is represented by an
Event
.
It is possible, but not necessary, for a process/activity to yield
/await
such a request to wait for its success.
- class usim.py.resources.base.BaseRequest(resource: usim.py.resources.base.BaseResource)[source]
Base class for
Put
andGet
eventsA request is commonly created via
put()
orget()
and must beyield
ed by a Process to wait until the request has been served. If a request has not been served but is no longer desired, the process shouldcancel
the request.A request can be used as a context manager to automatically cancel it at the end of the context. Note that the request is not automatically waited on – this must be done explicitly if desired.
with resource.get() as request: yield request
- cancel()[source]
Cancel the request
Requests should be cancelled when they have not been triggered but are no longer needed. This may happen when a process is interrupted while waiting for a request.
Cancelling is idempotent: If the request has already been triggered or canceled,
cancel()
can still be called without error.
- proc
the process that requested the action
- class usim.py.resources.base.Put(resource: usim.py.resources.base.BaseResource)[source]
Request to put content into a resource
- cancel()[source]
Cancel the request
Requests should be cancelled when they have not been triggered but are no longer needed. This may happen when a process is interrupted while waiting for a request.
Cancelling is idempotent: If the request has already been triggered or canceled,
cancel()
can still be called without error.
- class usim.py.resources.base.Get(resource: usim.py.resources.base.BaseResource)[source]
Request to get content out of a resource
- cancel()[source]
Cancel the request
Requests should be cancelled when they have not been triggered but are no longer needed. This may happen when a process is interrupted while waiting for a request.
Cancelling is idempotent: If the request has already been triggered or canceled,
cancel()
can still be called without error.
Containers – Continuous Resource Exchange
A Container
models the exchange of resources between processes:
processes may
produce resources and put()
them into the container, or
consume resources and get()
them out of the container.
These resources may be continuous (i.e. fractions can be exchanged) and
do not need to be conserved.
See also
Container
requests model permanent transfer of ownership:
processes may freely get()
and put()
content in and out of
the container.
In contrast, a Resource
models
temporary transfer of ownership.
- class usim.py.resources.container.Container(env, capacity: float = inf, init: float = 0)[source]
Resource with
capacity
of continuous, indistinguishable contentA Process may
get()
out orput()
in an arbitrary amount of content, provided thelevel
orcapacity
suffices. Requests that cannot be granted immediately are served once sufficientlevel
or capacity are available.- Parameters
capacity – the maximum amount of content available
init – the initial
level
of content available
By default, a
Container
has infinite capacity but starts empty. Note that it is not possible to have a higher initial content than maximum capacity.Hint
Migrating to μSim
The closest equivalent of a
Container
in μSim areResources
. Each contains multiple resource capacities which can be increased, decreased, set, borrowed or claimed individually or together. To emulate aContainer
, useResources
with a single resource type:resources = Resources(level=8) # put some content into the resource await resource.increase(level=8) # get some content from the resource await resource.decrease(level=8)
It is always safe to
increase()
,decrease()
orset()
resources – there is no need to cancel requests. To avoid leaking resources by not returning them, it is recommended to eitherborrow()
orclaim()
resources – this automatically returns the resources at the end of a scope.resources = Resources(apples=8, oranges=12) # borrow resources when available, returning them automatically async with resources.borrow(apples=2) as borrowed: print(f'temporarily got {borrowed.levels.apples} apples!')
When temporarily holding resources, this is represented by yet another resources instance. It can be passed around and further divided – but is guaranteed never to exceed what was taken from the initial resource.
- get(amount=1) usim.py.resources.container.ContainerGet [source]
Get
amount
of content out of the container
- put(amount=1) usim.py.resources.container.ContainerPut [source]
Put
amount
of content into the container
- class usim.py.resources.container.ContainerPut(container: usim.py.resources.container.Container, amount: float)[source]
Request to put
amount
of resources into thecontainer
- class usim.py.resources.container.ContainerGet(container: usim.py.resources.container.Container, amount: float)[source]
Request to get
amount
of resources out of thecontainer
Stores – Distinct Object Exchange
The Store
types implement various forms of queues:
an ordered container from which items can be removed and added.
Variants of the basic Store
support item priorities (PriorityStore
)
and item filtering (FilterStore
).
- class usim.py.resources.store.Store(env, capacity=inf)[source]
Resource with a fixed
capacity
of slots for storing arbitrary objectsA process can
put()
in specific items, provided there is enoughcapacity
. A process canget()
the next available item out of the store, provided there are any in the store. If thecapacity
is reached or if there are no items, the respective request is delayed.The
Store
serves objects in first-in-first-out order.Hint
Migrating to μSim
To pass items between activities, use a
Queue
. Queues store items for later retrieval:queue = Queue() # put an item into the queue await queue.put(1) # get an item out of the queue item = await queue
In addition to adding or retrieving individual items, it is possible to subscribe to a queue by iteration:
async for item in queue: print(item)
Even with several subscribers, a
Queue
yields every item only once.- get() usim.py.resources.store.StoreGet[usim.py.resources.store.T] [source]
Get an item out of the store
- property items: List[usim.py.resources.store.T]
The currently available items in the store
- put(item: usim.py.resources.store.T) usim.py.resources.store.StorePut[usim.py.resources.store.T] [source]
Put an
item
into the store
- class usim.py.resources.store.PriorityStore(env, capacity=inf)[source]
Resource with a fixed
capacity
of slots for storing arbitrary objects in orderThe
items
of the store are maintained in sorted order, with smaller items stored and served first. All items in the store must supporta < b
comparisons. To store unorderable items, usePriorityItem
.
- class usim.py.resources.store.PriorityItem(priority: float, item: Any)[source]
Helper to sort an unorderable
item
by apriority
This class implements a total ordering based on
priority
;item
is ignored for comparisons. This allows using an arbitraryitem
in aPriorityStore
with a well-definedpriority
.The original
simpy.resources.store.PriorityItem
only properly providesa < b
ordering; all other comparisons may compareitem
.usim.py
provides well-defined total ordering.- property item
Alias for field number 1
- property priority
Alias for field number 0
- class usim.py.resources.store.FilterStore(env, capacity=inf)[source]
Resource with a fixed
capacity
of slots for storing arbitrary objectsRequests to
get()
items support afilter
, which limits the objects that satisfy the request. A request may not be satisfied if the store contains only items that do not match the requestfilter
. Pending requests remain queued until a valid item appears in the store.While requests are served in first-in-first-out order, they are not granted in first-in-first-out order if items fail the
filter
of earlier requests. In addition, a request has to inspect all items in the store to conclude it cannot be granted. In the worst case, a store withn
items andm
request takesO(mn)
to get or put items.- get(filter: Callable[[usim.py.resources.store.T], bool] = <function accept_any>) usim.py.resources.store.FilterStoreGet[usim.py.resources.store.T] [source]
Get an item out of the store that satisfies
filter
- class usim.py.resources.store.StoreGet(resource: usim.py.resources.base.BaseResource)[source]
Request to get an
item
out of theresource
- class usim.py.resources.store.StorePut(store: usim.py.resources.store.Store, item: usim.py.resources.store.T)[source]
Request to put an
item
into thestore
- class usim.py.resources.store.FilterStoreGet(resource, filter: Callable[[usim.py.resources.store.T], bool] = <function FilterStoreGet.<lambda>>)[source]
Request to get an
item
out of theresource
if it passesfilter
The
filter
function is applied to allitems
of a store, and the first for whichfilter(item)
returnsTrue
is the result.