Skip to main content Link Menu Expand (external link) Document Search Copy Copied

Using an innocent way like this:

@app.route('/my/url/big.data')
async def my_big_data(content_type='application/octet-stream', **server):
    buffer_size = server['context'].options['buffer_size']

    with open('/my/folder/big.data', 'rb') as f:
        chunk = True

        while chunk:
            chunk = f.read(buffer_size)

            yield chunk

normally will not block the event loop. As long as the blocking io call open() and f.read() is quick (ie. You have a fast drive).

The subsequent calls to it (inside while chunk/True) is really safe. Thanks to the download speed limiter.

Internally, Tremolo will suspend each chunk / yield at some amount of time depending on the given speed setting. The lower speed setting given, the more chance for other coroutines to run.

Using a library like aiofiles should gives better performance.

Or reading the file in a separate thread with loop.run_in_executor:

from concurrent.futures import ThreadPoolExecutor

@app.route('/my/url/file.mp4')
async def my_video(content_type='video/mp4', **server):
    loop = server['loop']
    buffer_size = server['context'].options['buffer_size']

    def read_file():
        with open('/my/folder/file.mp4', 'rb') as f:
            chunk = True

            while chunk:
                chunk = f.read(buffer_size)

                yield chunk

    with ThreadPoolExecutor(max_workers=1) as executor:
        gen = read_file()
        data = True

        while data:
            data = await loop.run_in_executor(executor, gen.__next__)

            yield data

Note that this method may add some overhead compared to using the standar method.