Use asyncio in an IOC

There are two libraries available for asynchronous operations in PythonIOC: cothread and asyncio. This guide shows how to use the latter in an IOC.

Note

This page only explains the differences between using cothread and asyncio. For more thorough explanation of the IOC itself see Creating an IOC

# Import the basic framework components.
from softioc import softioc, builder, asyncio_dispatcher
import asyncio

# Create an asyncio dispatcher, the event loop is now running
dispatcher = asyncio_dispatcher.AsyncioDispatcher()

# Set the record prefix
builder.SetDeviceName("MY-DEVICE-PREFIX")

# Create some records
ai = builder.aIn('AI', initial_value=5)
ao = builder.aOut('AO', initial_value=12.45, always_update=True,
                  on_update=lambda v: ai.set(v))

# Boilerplate get the IOC started
builder.LoadDatabase()
softioc.iocInit(dispatcher)

# Start processes required to be run after iocInit
async def update():
    while True:
        ai.set(ai.get() + 1)
        await asyncio.sleep(1)

asyncio.run_coroutine_threadsafe(update(), dispatcher.loop)

# Finally leave the IOC running with an interactive shell.
softioc.interactive_ioc(globals())

The dispatcher is created and passed to iocInit(). This is what allows the use of asyncio functions in this IOC. It contains a new event loop to handle this.

The async update function will increment the value of ai once per second, sleeping that coroutine between updates. Note that we run this coroutine in the loop of the dispatcher, and not in the main event loop.

This IOC will, like the one in Creating an IOC, leave an interactive shell open. The values of the PVs can be queried using the methods defined in the softioc.softioc module.

Asynchronous Channel Access

PVs can be retrieved externally from a PV in an asynchronous manner by using the :py`aioca` module. It provides await-able implementations of caget, caput, etc. See that module for more information.