Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Activity api #2

Merged
merged 20 commits into from
Apr 25, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ All hard-to-use functionality is automatically scoped and managed, making it nat
.. code:: python3

# scoping is a builtin concept of usim
async with out(time >= 3000) as scope:
async with until(time >= 3000) as scope:
# complex tools are automatically managed
async for message in stream:
scope.do(handle(message))
Expand Down
33 changes: 29 additions & 4 deletions docs/source/glossary.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,23 @@
Glossary of Terms
=================

.. Using references in the glossary itself:
When mentioning other items, always reference them.
When mentioning the current item, never reference it.


.. glossary::

Activity
Ongoing action that drives forward a simulation - either through time or events.
Activities may be suspended and resumed as desired, or interrupted involuntarily.
Ongoing action that drives forward a simulation - either through :term:`time` or :term:`events <event>`.
Activities may be :term:`suspended <Suspension>` and resumed as desired, or interrupted involuntarily.

Time
Representation of the progression of a simulation.
Whereas the unit of time is arbitrary, its value always grows.

Time may only pass while all :term:`activities <Activity>` are *suspended*.
Time may only pass while all :term:`activities <Activity>`
are :term:`suspended <Suspension>` until a later time, not :term:`turn`.
An :term:`activity` may actively wait for the progression of time,
or implicitly delay until an event happens at a future point in time.

Expand All @@ -23,10 +28,30 @@ Glossary of Terms
Event
A well-defined occurrence at a specific point in :term:`time`.
Events may occur
as result of activities ("dinner is done"),
as result of activities ("when dinner is done"),
as time passes ("after 20 time units"),
or
at predefined points in time ("at 2000 time units"),

Notification
Information sent to an :term:`activity`, usually in response to an :term:`event`.
Notifications are only received when the :term:`activity`
is :term:`suspended <Suspension>`, i.e. at an ``await``, ``async for`` or ``async with``.

Postponement
:term:`Suspension` of an :term:`activity` until a later :term:`turn` at the same :term:`time`.
When an :term:`activity` is postponed, :term:`notifications <Notification>` may be received
and other :term:`activities <Activity>` may run but :term:`time` does not advance.

:note: μSim guarantees that all its primitives postpone on asynchronous operations.
This ensures that activities are reliably and deterministically interwoven.

Suspension
Pause the execution of an :term:`activity`,
allowing other :term:`activities <activity>` or :term:`time` to advance.
A suspended activity is only resumed when it receives a :term:`notification`.

Suspension can only occur as part of asynchronous statements:
waiting for the target of an ``await`` statement,
fetching the next item of an ``async for`` statement,
and entering/exiting an ``async with`` block.
2 changes: 1 addition & 1 deletion docs/source/tutorial/03_scopes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ We again use ``usim.time`` to track and influence the progression of our simulat
... await (time + 1) # 3
... drivers.do(deliver_one(3))
... print('Sent deliveries at', time.now) # 4.1
... print('-- Done deliveries at', time.now) # 4.2
... print('-- Done deliveries at', time.now) # 4.2

Scopes can be difficult because they are inherently about doing several things at once.
It helps to step through individual points of notice:
Expand Down
21 changes: 21 additions & 0 deletions docs/source/tutorial/04_cancel_scope.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@

Interlude 01: Interrupting Scopes
---------------------------------

.. code:: python3

>>> from usim import time, until
>>>
>>> async def deliver_one(which):
... print('Delivering', which, 'at', time.now)
... await (time + 5)
... print('Delivered', which, 'at', time.now)
>>>
>>> async def deliver_all(count=3):
... print('-- Start deliveries at', time.now)
... async with until(time + 10) as deliveries: # 1
... for delivery in range(count): # 2
... deliveries.do(deliver_one(delivery))
... await (time + 3)
... print('Sent deliveries at', time.now) # 4.1
... print('-- Done deliveries at', time.now) # 4.2
6 changes: 3 additions & 3 deletions usim/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@
from ._primitives.timing import Time, Eternity, Instant, each
from ._primitives.flag import Flag
from ._primitives.locks import Lock
from ._primitives.context import until, Scope, VolatileActivityExit
from ._primitives.activity import ActivityCancelled, ActivityState
from ._primitives.context import until, Scope, VolatileTaskExit
from ._primitives.task import TaskCancelled, TaskState


__all__ = [
'run',
'time', 'eternity', 'instant', 'each',
'until', 'Scope', 'ActivityCancelled', 'VolatileActivityExit', 'ActivityState',
'until', 'Scope', 'TaskCancelled', 'VolatileTaskExit', 'TaskState',
'Flag', 'Lock',
]

Expand Down
176 changes: 0 additions & 176 deletions usim/_primitives/activity.py

This file was deleted.

50 changes: 46 additions & 4 deletions usim/_primitives/condition.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,48 @@

class Condition(Notification):
"""
A logical condition that triggers when ``True``
An asynchronous logical condition

Every :py:class:`~.Condition` can be used both in an
asynchronous *and* boolean context.
In an asynchronous context,
such as ``await``,
a :py:class:`~.Condition` triggers when the :py:class:`~.Condition` becomes :py:const:`True`.
In a boolean context,
such as ``if``,
a :py:class:`~.Condition` provides its current boolean value.

.. code:: python

if condition: # resume with current value
print(condition, 'is met')
else:
print(condition, 'is not met')

await condition # resume when condition is True

async with until(condition): # abort if condition becomes False
async with until(condition): # interrupt when condition is True
...

Every :py:class:`~.Condition` supports the bitwise operators
``~a`` (not),
``a & b`` (and), and
``a | b`` (or)
to derive a new :py:class:`~.Condition`.
While it is possible to use the boolean operators
``not``, ``and``, and ``or``,
they immediately evaluate any :py:class:`~.Condition` in a boolean context.

.. code:: python

await (a & b) # resume when both a and b are True
await (a | b) # resume when one of a or b are True
await (a & ~b) # resume when a is True and b is False

c = a & b # derive new Condition...
await c # that can be awaited

d = a and b # force boolean evaluation
"""
__slots__ = ()

Expand Down Expand Up @@ -88,7 +122,11 @@ def __repr__(self):


class All(Connective):
"""Logical AND of all sub-conditions"""
"""
Logical AND of all sub-conditions

The expression ``a & b & c`` is equivalent to ``All(a, b, c)``.
"""
__slots__ = ()

def __bool__(self):
Expand All @@ -102,7 +140,11 @@ def __str__(self):


class Any(Connective):
"""Logical OR of all sub-conditions"""
"""
Logical OR of all sub-conditions

The expression ``a | b | c`` is equivalent to ``Any(a, b, c)``.
"""
__slots__ = ()

def __bool__(self):
Expand Down
Loading