question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

'IndexError: pop from empty list' Exception in Queue (V3) due to uncleared _evput state

See original GitHub issue

This is using the temporary V3 Queue. Not sure if Im wasting my breath if there is already a new version somewhere else (at least I dont know of it…)? Anyway, I used this one and ran into a tad bit of an annoyance 😃

Due to some “unfortunate” scheduling of routines, one can get greeted by a lovely “IndexError: pop from empty list” in the get() method of queue, where one would expect it to wait if the queue is empty - sadly doesn’t always work…

I believe I found the reason (and fix) but first a minimal example and my explanation.

import uasyncio as asyncio
import Queue


async def putter(q, sleep_ms=50):
    # put some item, then sleep
    while True:
        await q.put(1)
        await asyncio.sleep_ms(sleep_ms)


async def getter(q):
   # checks for new items, and relies on the "blocking" of the get method
    while True:
        print(await q.get())


async def task():
    q = Queue()

    await asyncio.gather(
        putter(q),
        getter(q)
    )

asyncio.run(task())

The error appears only under some (scheduling) circumstances. One instance is:

  • if the putter routine is called first, meaning some item is placed in the queue, making it not empty and the _evput will be set (https://github.com/peterhinch/micropython-async/blob/master/v3/primitives/queue.py#L47).
  • if now the getter method is executed, it will return the item placed in queue as the ‘if self.empty():’ check (https://github.com/peterhinch/micropython-async/blob/master/v3/primitives/queue.py#L34) will evaluate to False.
  • if the getter methods now goes for the next iteration, BEFORE another item is placed (for example due to the putter method sleeping or some scheduling happenstance), the L34 check will now be True as the queue is empty, however, the L36 call ‘await self._evput.wait()’ will immediately return as the _evput is still set, since we never cleared it. Clearing only happens after an empty queue was awaited and a new item was put.

So, a proposal solution is:

    async def get(self):  #  Usage: item = await queue.get()
        if self.empty():
            # Queue is empty, put the calling Task on the waiting queue
            await self._evput.wait()
        self._evput.clear()
        return self._get()

Not sure if causes other problems, that I didnt consider due to 1.30 am tiredness, but ye. But I guessed, regardles of whether self.empty() was True or False, if the ‘self._evput.clear()’ is reached, some item was placed by now (and it will be set, so I guess we dont need any check about it…) I can also make a PR tomorrow after work if you agree that is a bug after all.

PS: In https://github.com/peterhinch/micropython-async/blob/master/v3/primitives/queue.py#L51 and https://github.com/peterhinch/micropython-async/blob/master/v3/primitives/queue.py#L59 it should be preferable to have

if self.maxsize and self.qsize() >= self.maxsize:

instead of the current

if self.qsize() >= self.maxsize and self.maxsize:

?

I believe Python evaluates boolean conditions lazily, meaning ‘if self.maxsize’ evaluates to false, we save ourself the second evaluation. Albeit we should probably check for ‘if self.maxsize > 0’, as we do not check or otherwise validate negative inputs. In the cpython/official version, negative numbers are treated like 0 that way and imply infinite size.

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Comments:11 (11 by maintainers)

github_iconTop GitHub Comments

1reaction
dbadriancommented, Oct 3, 2020

Understood, thanks. I hope to get back to my project soon and then I’ll give it a review/testing and close it after.

0reactions
peterhinchcommented, Nov 25, 2022

Closing as I believe this is fixed.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Index error: pop from empty list - python - Stack Overflow
The indexes in a list starts from zero. So, in more_stuff[7] you will get 'Boy' which is the last one. Your code is...
Read more >
Annoying "IndexError: pop from empty list" : r/learnpython
So, I'll have to use exceptions in order to catch it? Will the program stop when it triggers or will it continue as...
Read more >
rhui-manager shows "IndexError: pop from empty list"
After delete all repositories on rhui-manager , entering 'r' (manage repositories) to add repository on rhui-manager shows an error like:.
Read more >
pop from empty list in grad_sample_module.py for opacus ...
Hi, Im using Opacus to make CT-GAN (GitHub - sdv-dev/CTGAN: Conditional GAN for generating synthetic tabular data.) differntial private.
Read more >
IndexError: pop from empty list in Python | bobbyhadz
The Python IndexError: pop from empty list occurs when we call the `pop()` method on an empty list. To solve the error, use...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found