Skip to content

Commit 12967f8

Browse files
authored
Merge pull request #23 from dls-controls/asyncio_docs
Clarify asyncio vs cothread
2 parents 3356f44 + 8b54665 commit 12967f8

File tree

3 files changed

+109
-7
lines changed

3 files changed

+109
-7
lines changed
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
What are the differences between `asyncio` and `cothread`?
2+
==========================================================
3+
4+
There are two concurrency frameworks that pythonSoftIOC supports, `asyncio` and
5+
`cothread`. This page details the differences between them and reasons why you
6+
should use one over the other
7+
8+
.. seealso::
9+
10+
`../how-to/use-asyncio-in-an-ioc` for an example of how to use asyncio and
11+
pythonSoftIOC
12+
13+
14+
The Similarities
15+
----------------
16+
17+
Both frameworks are asynchronous concurrency frameworks, which means that they
18+
run in a single OS thread, and use lightweight coroutines/cothreads for
19+
concurrency. These are more deterministic and use less resources than OS
20+
threads, which makes them well suited to applications like pythonSoftIOC where
21+
many records may be processing concurrently. The biggest advantage is that only
22+
one coroutine runs at any one time. A coroutine will run until it yields control
23+
to another coroutine. This means that changes to shared state can only occur
24+
when it has yielded control, which reduces the need for mutexes that would be
25+
needed in threaded code.
26+
27+
28+
The Differences
29+
---------------
30+
31+
The main difference between the libraries is how a coroutine yields control.
32+
33+
- `asyncio` uses an ``async def`` which will yield control when they ``await``.
34+
Only an ``async def`` can ``await`` another ``async def``, so functions that
35+
yield control are explicitly marked as such by the presence of the ``async``
36+
keyword.
37+
- `cothread` has the :func:`~cothread.Yield` function which can be used in any
38+
ordinary ``def``. The yield is implicit as you need to read the
39+
documentation/source code to find out if a function will yield control
40+
41+
For example, an `on_update` function written using cothread might be::
42+
43+
import cothread
44+
from softioc import builder
45+
46+
def something_that_yields_control(value):
47+
cothread.Sleep(0.1)
48+
49+
def update_ao(value):
50+
something_that_yields_control(value)
51+
print(value)
52+
53+
builder.aOut('AO', on_update=update_ao)
54+
55+
While the same example written using asyncio is::
56+
57+
import asyncio
58+
from softioc import builder
59+
60+
async def something_that_yields_control(value):
61+
await asyncion.sleep(0.1)
62+
63+
async def update_ao(value):
64+
await something_that_yields_control(value)
65+
print(value)
66+
67+
builder.aOut('AO', on_update=update_ao)
68+
69+
Note that because ``something_that_yields_control()`` is an ``async def``,
70+
``update_ao()`` needs to be too.
71+
72+
.. seealso::
73+
74+
https://glyph.twistedmatrix.com/2014/02/unyielding.html for a discussion on
75+
explicit vs implicit yield
76+
77+
78+
Which to use
79+
------------
80+
81+
There are some questions to ask to help you choose which one to use:
82+
83+
- If you run python2.7 then you need to use `cothread` as `asyncio` is python3
84+
only
85+
- If you run on Windows then you need `asyncio` as `cothread` doesn't work on
86+
Windows
87+
- If you need to integrate with a library that uses `asyncio` like one from
88+
aio-libs_ then use `asyncio`
89+
- If you need to turn a script using `cothread.catools` into an IOC then use
90+
`cothread`
91+
92+
In general, avoid mixing concurrency frameworks if you can. While it is possible
93+
to mix `asyncio` and `cothread`, it's messy and tricky to get right. Better to
94+
keep to one if possible.
95+
96+
.. _aio-libs: https://github.com/aio-libs
97+
98+

docs/how-to/use-asyncio-in-an-ioc.rst

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,19 @@
11
Use `asyncio` in an IOC
22
=======================
33

4-
There are two libraries available for asynchronous operations in pythonSoftIOC:
5-
`cothread` and `asyncio`. This guide shows how to use the latter in
6-
an IOC.
4+
`../tutorials/creating-an-ioc` shows how to create a pythonSoftIOC using the
5+
`cothread` library. This page shows how to create one using `asyncio`
76

8-
.. note::
9-
This page only explains the differences between using `cothread` and `asyncio`.
10-
For more thorough explanation of the IOC itself see `../tutorials/creating-an-ioc`
7+
.. seealso::
8+
9+
`../explanations/asyncio-cothread-differences` for the differences and why
10+
you would use one over the other
1111

12-
.. literalinclude:: ../examples/example_asyncio_ioc.py
1312

13+
Example IOC
14+
-----------
15+
16+
.. literalinclude:: ../examples/example_asyncio_ioc.py
1417

1518
The ``dispatcher`` is created and passed to :func:`~softioc.softioc.iocInit`. This is what
1619
allows the use of `asyncio` functions in this IOC. It contains a new event loop to handle

docs/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ Table Of Contents
6969
:maxdepth: 1
7070

7171
explanations/why-use-pythonSoftIOC
72+
explanations/asyncio-cothread-differences
7273

7374
.. rst-class:: no-margin-after-ul
7475

0 commit comments

Comments
 (0)