And Now, For Something Completely Different
The Grand Experiment
In writing Xi, I learned the importance and power of non-blocking asynchronous io. Xi is written in JavaScript, but my language of preference is Python, so I decided to explore Python's alternatives to node.js.
I looked at many options. Gevent, Stackless Python, Twisted, the Python asyncio library, as well as others. What interested me most was asyncio. My reasoning here is that is part of the Python 3.4.2+ library (batteries included), and it supports concurrency without having to resort to callbacks. It performs this magic through coroutines.
Knowing the direction I wanted to go towards, I read the literature, looked at examples, and gave myself a simple task to solve. The task was to be able to read and process the relentless data stream sent by an Arduino Esplora running the Arduino sketch included with esp4s program, using nothing but asyncio coroutines.
Believing I was fully educated, I wrote some code, started up Python, and low and behold, I got a screen full of exceptions. It became abundantly clear that I was clueless when it came to coroutines, especially asyncio coroutines.
Back to the Classroom with My Tail Between My Legs
Time to go on a Google hunt for examples to emulate. All I could find were ways to concurrently calculate a Fibonacci sequence, or open up thousands of web connections. Neither of these examples helped me solve my self-assigned problem of continuously receiving a stream of serial data without pinning the CPU utilization meter.
It became perfectly clear that looking at the available examples just wasn't enough. It was time to really learn about the nuts and bolts of coroutines and the related topic of generators. There is a ton of literature on the interwebs on these subjects, but I could find nothing that directly related to helping me solve my problem. I finally came across a link to a Dave Beazley talk entitled, "Generator Tricks for System Programmers". After reviewing the slides, I began to understand the real utility of using generators. My education was partly complete. I checked out another Dave Beazley talk, "A Curious Course on Coroutines and Concurrency". Dave explains coroutines in a way that a mere mortal like me could readily understand. Now I was hooked. So I continued with Dave's trilogy and not only looked at the slides for "Generators - The Final Frontier", but watched the YouTube video as well - from beginning to end - a first for me. Now, I have to warn you, this is a 3 hour video, and it took me a couple of days to get through it. Not because I needed to take a nap between viewings, but because the material was so mind blowing, that I needed to take breaks to absorb it. The last piece of my coroutine crash course was to watch Dave's 2015 PyCon presentation, "Python Concurrency From the Ground Up". A mere 30 minute presentation that is chock full of goodies.
I started with something simple. A consumer/producer program using asyncio coroutines. It actually worked - no exceptions mocking me this time. Encouraged, I went on to solving my original problem of processing streaming data coming from an Arduino Esplora using eps4s. Surprise, surprise - this actually worked too!
Ecstatic, I decided to prototype a total asyncio rendition of esp4s. The esp4s program allows a user to control and monitor an Arduino Esplora board using the Scratch or Snap! programming languages.
The Grand Experiment, Take 2
Now Dave does't cover the asyncio library per se (hey Dave, if you are reading, how about an asyncio talk for PyCon 2016?), but feeling I was armed with a pretty solid understanding of coroutines, I would try and slay the asyncio dragon once again.I started with something simple. A consumer/producer program using asyncio coroutines. It actually worked - no exceptions mocking me this time. Encouraged, I went on to solving my original problem of processing streaming data coming from an Arduino Esplora using eps4s. Surprise, surprise - this actually worked too!
Ecstatic, I decided to prototype a total asyncio rendition of esp4s. The esp4s program allows a user to control and monitor an Arduino Esplora board using the Scratch or Snap! programming languages.
The esp4s software is sandwiched in-between the serial data stream coming from the Esplora, and the HTTP status polls and actuator commands coming from a Scratch project. A new Esplora status frame arrives every 25 ms, and a new Scratch poll request arrives every 33 ms. Neither are flow controlled and both are fully asynchronous. The esp4s processes these streams and acts as a data translator between the Esplora and Scratch project.
For the prototype of esp4s-aio, the software accepts all status frames from Esplora, processes 4 of the 16 status types (to add load), and sends them to the Scratch script. Concurrently, it receives the poll requests and responds with the latest status data and in addition, concurrently receives a separate stream of commands from the Scratch script to control the Esplora. For the prototype, I created a Scratch script to blink the red LED on the board.
The esp4s program is being pushed and pulled from all directions!
The Results
So was all this effort worth it? Here is a screen shot of CPU utilization while running the threaded version of esp4s:
And here is the prototype using asyncio coroutines:
It looks like I can have my cake (writing in Python), and eat it too (have the concurrency of node.js)!
What's Next?
In the coming weeks I will be completing and unit testing the code.
Once this is all complete, I will be publishing esp4s-aio.
Stay Tuned!
No comments:
Post a Comment