Skip to content

Commit 72a3a87

Browse files
committed
Fix links in concurrency page
1 parent 3e69204 commit 72a3a87

File tree

1 file changed

+11
-4
lines changed

1 file changed

+11
-4
lines changed

docs/source/concurrency.rst

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,18 @@ One of the major challenges when controlling hardware, particularly from web fra
55

66
LabThings-FastAPI instantiates each :class:`.Thing` only once, and runs all code in a thread. More specifically, each time an action is invoked via HTTP, a new thread is created to run the action. Similarly, each time a property is read or written, a new thread is created to run the property method. This means that :class:`.Thing` code should protect important variables or resources using locks from the `threading` module, and need not worry about writing asynchronous code.
77

8-
In the case of properties, the HTTP response is only returned once the :class:`.Thing` code is complete. Actions currently return a response immediately, and must be polled to determine when they have completed. This behaviour may change in the future, most likely with the introduction of a timeout to allow the client to choose between waiting for a response or polling.
8+
In the case of properties, the HTTP response is only returned once the `.Thing` code is complete. Actions currently return a response immediately, and must be polled to determine when they have completed. This behaviour may change in the future, most likely with the introduction of a timeout to allow the client to choose between waiting for a response or polling.
99

10-
Many of the functions that handle HTTP requests are asynchronous, running in an :mod:`anyio` event loop. This enables many HTTP connections to be handled at once with good efficiency. The interface between async and threaded code is provided by a :class:`anyio.BlockingPortal`, created when the LabThings server is started. A FastAPI Dependency allows the blocking portal to be obtained: while it's very unlikely more than one LabThings server will exist in one Python instance, we avoid referring to the blocking portal globally in an effort to avoid concurrency issues.
10+
Many of the functions that handle HTTP requests are asynchronous, running in an :mod:`anyio` event loop. This enables many HTTP connections to be handled at once with good efficiency. The `anyio documentation`_ describes the functions that link between async and threaded code. When the LabThings server is started, we create an :class:`anyio.from_thread.BlockingPortal`, which allows threaded code to run code asynchronously in the event loop.
1111

12-
If threaded code needs to call code in the `anyio` event loop, the :class:`~.dependencies.blocking_portal.BlockingPortal` dependency should be used. There are relatively few occasions when :class:`.Thing` code will need to consider this explicitly: more usually the blocking portal will be obtained by a LabThings function, for example the :class:`.MJPEGStream` class.
12+
An action can obtain the blocking portal using the `~labthings_fastapi.dependencies.blocking_portal.BlockingPortal` dependency, i.e. by declaring an argument of that type. This avoids referring to the blocking portal through a global variable, which could lead to confusion if there are multiple event loops, e.g. during testing.
1313

14-
When one `Thing` calls the actions or properties of another :class:`.Thing`, either directly or via a :class:`.DirectThingClient`, no new threads are spawned: the action or property is run in the same thread as the caller. This mirrors the behaviour of the :class:`.ThingClient`, which blocks until the action or property is complete.
14+
There are relatively few occasions when `.Thing` code will need to consider this explicitly: more usually the blocking portal will be obtained by a LabThings function, for example the `.MJPEGStream` class.
15+
16+
.. _`anyio documentation`: https://anyio.readthedocs.io/en/stable/threads.html
17+
18+
Calling Things from other Things
19+
--------------------------------
20+
21+
When one `Thing` calls the actions or properties of another `.Thing`, either directly or via a `.DirectThingClient`, no new threads are spawned: the action or property is run in the same thread as the caller. This mirrors the behaviour of the `.ThingClient`, which blocks until the action or property is complete. See :doc:`using_things` for more details on how to call actions and properties of other Things.
1522

0 commit comments

Comments
 (0)