This test case uses OpenCV to open a video file and asynchronously process each frame of the video. The "processing" in this case is slow, mocked up as an asynchronous 15 seconds of background operations.

Before we continue, we've used a couple of new patterns here. The first is the call to ensure_future. Calling a coroutine function (like "process_frame") only returns a coroutine object (the terminology is confusing here, as both the function and the object returned can be casually referred to as a "coroutine"). Creating a coroutine object does not begin or schedule execution of the coroutine. To do that, you must either await the coroutine object or explicitly schedule it, which ensure_future does. In this case we do not want to immediately await the coroutine since that would result in the pipeline being executed synchronously — read a frame, process it, wait for the result to complete, and then read the next frame. So instead we pass it to ensure_future.

Once we call ensure_future, we then call asyncio.sleep(0). This is a pattern to relinquish control of the pipeline back to the event loop, which will allow the asynchronous processing of the video frame we just read to begin. This pattern might look familiar to multithreaded programmers in say, C++, where an explicit sleep(0) call from a thread might (depending on the platform) cause it to relinquish the remainder of its time slice to another thread that is ready to run. In this case, however, it's absolutely necessary, as there's no other mechanism to relinquish control of the event loop other than to explicitly await another Future. If this call wasn't here, the entire reading of the video file would complete before any processing of the frames would begin. This pattern might seem ugly or unintuitive, but alternatives have been discussed and this one has been explicitly approved by Guido.

The memory problem

Going back to the primary logic of our video processing pipeline, you might already guess what the issue is going to be. Our individual frame processing is very slow, and we have made no attempt to throttle the reading of a video input of arbitrary length and size. If we attempt to run our pipeline on this 4K honey bee video, our memory usage starts to spiral out of control: