cpython icon indicating copy to clipboard operation
cpython copied to clipboard

wait_for(coro, timeout=0) memleak

Open dd3db5ee-f287-4f3c-8fe6-7240e020a247 opened this issue 6 years ago • 7 comments

BPO 37042
Nosy @asvetlov, @1st1, @ixje
Files
  • test_leak_minimal.py: minimal example that bleeds memory
  • test_leak_minimal_mem_consumption.png
  • Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

    Show more details

    GitHub fields:

    assignee = None
    closed_at = None
    created_at = <Date 2019-05-25.12:09:54.889>
    labels = ['expert-asyncio', '3.7', 'performance']
    title = 'wait_for(coro, timeout=0) memleak'
    updated_at = <Date 2019-05-25.12:34:53.128>
    user = 'https://github.com/ixje'
    

    bugs.python.org fields:

    activity = <Date 2019-05-25.12:34:53.128>
    actor = 'ixje'
    assignee = 'none'
    closed = False
    closed_date = None
    closer = None
    components = ['asyncio']
    creation = <Date 2019-05-25.12:09:54.889>
    creator = 'ixje'
    dependencies = []
    files = ['48356', '48357']
    hgrepos = []
    issue_num = 37042
    keywords = []
    message_count = 6.0
    messages = ['343470', '343472', '343473', '343475', '343476', '343477']
    nosy_count = 3.0
    nosy_names = ['asvetlov', 'yselivanov', 'ixje']
    pr_nums = []
    priority = 'normal'
    resolution = None
    stage = None
    status = 'open'
    superseder = None
    type = 'resource usage'
    url = 'https://bugs.python.org/issue37042'
    versions = ['Python 3.7']
    

    I have a networked process that looks somewhat like this in its most basic form

    import asyncio
    
    shutting_down = False
    
    async def read_message(reader, timeout=30):
        async def _read(reader: asyncio.StreamReader):
            try:
                d = await reader.readexactly(24)
                # do something with the data
                print("I'm never called")
            except:
                return None
    
        try:
            return await asyncio.wait_for(_read(reader), timeout)
        except Exception:
            return None
    
    
    async def my_service():
        reader, writer = await asyncio.open_connection('127.0.0.1', 20333)
        while not shutting_down:
            m = await read_message(reader, timeout=0)
            if m is None:
                continue
            # else process message
    
    
    if __name__ == "__main__":
        loop = asyncio.get_event_loop()
        loop.create_task(my_service())
        loop.run_forever()
    

    read_message() has a default timeout of 30, but I thought setting it to 0 (instead of None) would be equal to blocking. This bleeds 16GB of memory in ~3 minutes. A minimal example is provided.

    I manually applied the patch of https://bugs.python.org/issue36613 to a self compiled build of 3.7.3 (https://github.com/python/cpython/commit/ef4ec6ed12d6c6200a85068f60483723298b6ff4) on Ubuntu 18.04 and that did not solve the problem.

    Thanks for the report. If the problem is in asyncio.wait_for() function the real network code can be stripped for the leakage example and replaced with await asyncio.sleep().

    Would you try to boil down the snippet by converting it into a code that I can execute on my laptop to reproduce the problem?

    asvetlov avatar May 25 '19 12:05 asvetlov

    Hi Andrew, There is an attached minimal example (that differs from the code given in the first comment). I couldn't attach 2 files. So I pasted the code of one file to showcase how we could run into the issue, then a minimal reproducible example without network code in the attachment.

    Nice, thanks!

    asvetlov avatar May 25 '19 12:05 asvetlov

    This is the consumption I'm seeing.

    Perhaps also worth mentioning is that when we supply None as timeout value in the wait_for() in the minimal sample, then it still reports 60MB memory usage. Seems pretty steep for doing basically nothing but looping around.

    I am unable to reproduce the leak on main branch. I profiled with memray and the rss usage is constant.

    newplot

    kumaraditya303 avatar Aug 15 '22 08:08 kumaraditya303

    @kumaraditya303 were you able to reproduce it with 3.7?

    iritkatriel avatar Aug 26 '22 09:08 iritkatriel

    I tried myself - indeed I can reproduce it on 3.7 but no on main (on a MAC).

    iritkatriel avatar Aug 26 '22 10:08 iritkatriel