Asyncio support¶
The asyncio
module built into Python 3.4 and later can be used to write
asynchronous code in a single thread. This library supports receiving messages
asynchronously in an event loop using the can.Notifier
class.
There will still be one thread per CAN bus but the user application will execute entirely in the event loop, allowing simpler concurrency without worrying about threading issues. Interfaces that have a valid file descriptor will however be supported natively without a thread.
You can also use the can.AsyncBufferedReader
listener if you prefer
to write coroutine based code instead of using callbacks.
Example¶
Here is an example using both callback and coroutine based code:
import asyncio
import can
def print_message(msg):
"""Regular callback function. Can also be a coroutine."""
print(msg)
async def main():
can0 = can.Bus('vcan0', bustype='virtual', receive_own_messages=True)
reader = can.AsyncBufferedReader()
logger = can.Logger('logfile.asc')
listeners = [
print_message, # Callback function
reader, # AsyncBufferedReader() listener
logger # Regular Listener object
]
# Create Notifier with an explicit loop to use for scheduling of callbacks
loop = asyncio.get_event_loop()
notifier = can.Notifier(can0, listeners, loop=loop)
# Start sending first message
can0.send(can.Message(arbitration_id=0))
print('Bouncing 10 messages...')
for _ in range(10):
# Wait for next message from AsyncBufferedReader
msg = await reader.get_message()
# Delay response
await asyncio.sleep(0.5)
msg.arbitration_id += 1
can0.send(msg)
# Wait for last message to arrive
await reader.get_message()
print('Done!')
# Clean-up
notifier.stop()
can0.shutdown()
# Get the default event loop
loop = asyncio.get_event_loop()
# Run until main coroutine finishes
loop.run_until_complete(main())
loop.close()