Resource Modelling¶
Resource Containers¶
Resources support the comparison operations, such as ==
, >=
, or <
.
This derives a Comparison
that triggers when the Resources’
levels reaches the desired value.
- class usim.Resources(__zero__: Optional[usim._basics.resource.T] = None, **capacity: usim._basics.resource.T)[source]¶
Supply of named resources which can be temporarily borrowed or produced/consumed
The resources and their initial levels are defined when the resource supply is created. Afterwards, the level of resources can be permanently
increase()
d ordecrease()
d as well as temporarily decreased byborrow()
ing:# create an open supply of resources resources = Resources(cores=8, memory=4000) # increase the resource supply available await resources.increase(memory=2000) # temporarily remove resources async with resources.borrow(cores=2, memory=6000): await computation # decrease the resource supply available await resources.decrease(cores=4)
A
Capacities
guarantees that it is always possible to increase the level of available resources. Once resources areborrow()
ed, they can always be returned promptly.- await decrease(**amounts: usim._basics.resource.T)[source]¶
Decrease the level of resources
- Parameters
amounts – resource levels to decrease
Only levels of resources that are already part of these
Resources
can be decreased. Levels cannot be decreased by negative amounts or below zero. If a resource is not specified, its level remains unchanged.
- await increase(**amounts: usim._basics.resource.T)[source]¶
Increase the level of resources
- Parameters
amounts – resource levels to increase
Only levels of resources that are already part of these
Resources
can be increased. Levels cannot be increased by negative amounts. If a resource is not specified, its level remains unchanged.
- class usim.Capacities(__zero__: Optional[usim._basics.resource.T] = None, **capacity: usim._basics.resource.T)[source]¶
Fixed supply of named resources which can be temporarily borrowed
The resources and their maximum capacity are defined when the resource supply is created. Afterwards, it is only possible to temporarily
borrow()
resources:# create a limited supply of resources resources = Capacities(cores=8, memory=16000) # temporarily remove resources async with resources.borrow(cores=2, money=4000): await computation
A
Capacities
guarantees that its resources are conserved and cannot be leaked. Once resources areborrow()
ed, they can always be returned promptly.
- class usim.typing.ResourceLevels(**kwargs: usim._basics._resource_level.T)[source]¶
Common class for named resource levels
Representation for the levels of multiple named resources. Every set of resources, such as
usim.Resources
orusim.Capacities
, specializes aResourceLevels
subclass with one attribute for each named resource. For example,Resources(a=3, b=4)
uses aResourceLevels
with attributesa
andb
.from usim import Resources resources = Resources(a=3, b=4) print(resources.levels.a) # 3 print(resources.levels.b) # 4 print(resources.levels.c) # raises AttributeError
ResourceLevels
subtypes allow no additional attributes other than their initial resources, but their values may be changed. Instantiating a subtype requires resource levels to be specified by keyword; missing resource are set to zero.Each resource always uses the same
ResourceLevels
subtype. Binary operators for comparisons and arithmetic can be applied for instances of the same subtype.- levels_a + levels_b
- levels_a - levels_b
Elementwise addition/subtraction of values.
- levels_a > levels_b
- levels_a >= levels_b
- levels_a <= levels_b
- levels_a < levels_b
Strict elementwise comparison of values.
True
if the comparison is satisfied by each element pair,False
otherwise.
- levels_a == levels_b
Total elementwise equality of values.
True
if each element pair is equal,False
otherwise. The inverse oflevels_a != levels_b
.
- levels_a != levels_b
Partial elementwise unequality of values.
False
if each element pair is equal,True
otherwise. The inverse oflevels_a == levels_b
.
In addition, iteration on a
ResourceLevels
subtype yieldsfield, value
pairs. This is similar todict.items()
.- for field, value in levels_a
Iterate over the current
field, value
pairs.
- dict(levels_a)
Create
dict
offield: value
pairs.
Resources requested from a supply are not available
Resource Transfer¶
- class usim.Pipe(throughput: float)[source]¶
Shared transport for resources with a limited total throughput
- Parameters
throughput – limit of total throughput
The throughput limit of a pipe is defined when a
Pipe
is created. Afterwards, activities may temporarily request transfers through thePipe
with a maximum throughput. If the sum of throughput from all transfers exceeds the throughput limit, transfers are throttled accordingly.connection = Pipe(throughput=3) # transfers below limit await connection.transfer(total=10, throughput=2) # takes 5 time units # transfers above limit async with Scope() as scope: # takes 10 time units scope.do(connection.transfer(15, throughput=3) scope.do(connection.transfer(15, throughput=3)
- await transfer(total: float, throughput: Optional[float] = None) → None[source]¶
Wait until some total volume has been transferred
- Parameters
total – absolute volume to transfer before resuming
throughput – maximum throughput of transfer
The effective
throughput
is bounded by the transfer’sthroughput
as well as the Pipe’sthroughput
weighted by all transfers’throughput
. For example, if two transfers each request the entirethroughput
, each receives only half.network = Pipe(throughput=64) await network.transfer(total=50 * 1024, throughput=128) # transfer with 64
If
throughput
is not given, it defaults to the Pipe’sthroughput
limit.
- class usim.UnboundedPipe(throughput=inf)[source]¶
Shared transport for resources with unlimited total throughput
This is a noop variant of the regular
Pipe
. It serves as a neutral element when aPipe
is required but no throttling should take place.- await transfer(total: float, throughput: Optional[float] = None) → None[source]¶
Wait until some total volume has been transferred
- Parameters
total – absolute volume to transfer before resuming
throughput – maximum throughput of transfer
The effective
throughput
is bounded by the transfer’sthroughput
as well as the Pipe’sthroughput
weighted by all transfers’throughput
. For example, if two transfers each request the entirethroughput
, each receives only half.network = Pipe(throughput=64) await network.transfer(total=50 * 1024, throughput=128) # transfer with 64
If
throughput
is not given, it defaults to the Pipe’sthroughput
limit.