Skip to content

how to use memory_profiler to test async function #289

Open

Description

@leiyugithub

async def test(loop):
s = time.time() * 1000

Activity

  1. ZoidbergPi commented on Oct 17, 2020

    @ZoidbergPi

    see PR: #255 it seems added support @asyncio.coroutine in python3.4 by @d-ryzhikov, but it didn't work for async def mark in python3.5+

  2. d-ryzhykau commented on Oct 17, 2020

    @d-ryzhykau
    Contributor

    @ZoidbergPi , using @profile decorator with async def syntax works as well since my PR has been merged as this is essentially the same thing as using @asyncio.coroutine decorator. The test of asyncio support added in my PR is using asyncio.couroutine because to support python3.4, because async def-syntax has been introduced in python.3.5

    @leiyugithub , even though my PR has been merged, there were no new releases of this library since. To use this functionality you either have to install the package from github, or ask the maintainer to create and publish a new release to PyPI.

  3. fabianp commented on Oct 19, 2020

    @fabianp
    Collaborator
  4. Hazhzeng commented on Mar 22, 2021

    @Hazhzeng

    Hi @d-ryzhikov, I just tested it with async def syntax with the latest release 0.58.0 on Python 3.8.1, and the return value is still None.

    import asyncio
    import memory_profiler
    
    def main():
        result = asyncio.run(my_double_async(1))
        print(result)
    
    @memory_profiler.profile
    async def my_double_async(a: int):
        b = a * 2
        return b
    
    main()

    Result as below:

    Line #    Mem usage    Increment  Occurences   Line Contents
    ============================================================
         8     18.6 MiB     18.6 MiB           1   @memory_profiler.profile
         9                                         async def my_double_async(a: int):
        10     18.6 MiB      0.0 MiB           1       b = a * 2
        11     18.6 MiB      0.0 MiB           1       return b
    
    
    None
    

    Commenting the line @memory_profiler.profile yields the proper return value 2.
    Is there any way to mitigate this issue? Thanks.

  5. d-ryzhykau commented on Mar 22, 2021

    @d-ryzhykau
    Contributor

    @Hazhzeng , this is a bug. Thank you for catching it. I will prepare a PR fixing this a bit later today.

  6. vertillo commented on Sep 20, 2021

    @vertillo

    If you try to await an async function that awaits for other async functions it doesn't work

  7. d-ryzhykau commented on Sep 25, 2021

    @d-ryzhykau
    Contributor

    Hello @anphetamina. Could you please provide steps to replicate your problem?

  8. chr1st1ank commented on Feb 2, 2022

    @chr1st1ank

    How is this supposed to work?

    I just tried profiling an async function with @memory_profiler.profile just as in @Hazhzeng 's example above and the output also looks like above. I'm getting something like:

    Line #    Mem usage    Increment  Occurrences   Line Contents
    =============================================================
        16    301.0 MiB    301.0 MiB           1   @memory_profiler.profile
        17                                         async def calculate_metrics(sizes):
        18    301.0 MiB      0.0 MiB           1       metrics = dict(index_time_s=[], memory_bytes=[], query_time_s=[])
        19    301.0 MiB      0.0 MiB           1       threshold = 0.8
        20              
                     .... more function body ...
    

    Increment 0.0 everywhere.

    Where I put .... more function body ... is the actual code which allocates memory heavily and which I would like to profile. Now I just have the 301MB on the line with the decorator and no increment below.
    If I comment out the rest of the function body the number stays the same.
    In the example by @Hazhzeng it seems to be just the same issue.

    Edit:
    Python 3.9.9
    memory_profiler 0.60.0

  9. d-ryzhykau commented on Feb 2, 2022

    @d-ryzhykau
    Contributor

    Hello @chr1st1ank. First of all, please, note that @Hazhzeng's issue was related to decorated functions not returning the correct value.
    Also, please, note that the amount of allocated memory has been 301.0 MiB starting from line 16, before the function execution started. Lines 18 and 19 are displayed to add 0 memory only because their impact is minimal. Only large memory increments are tracked and displayed.

    Here is an example that I used to test locally (Python 3.9.9, memory_profiler==0.60.0):

    Line #    Mem usage    Increment  Occurrences   Line Contents
    =============================================================
         6     18.1 MiB     18.1 MiB           1   @profile
         7                                         async def foo():
         8     25.9 MiB      7.7 MiB           1       a = [1] * (10 ** 6)
         9    178.2 MiB    152.4 MiB           1       b = [2] * (2 * 10 ** 7)
        10    178.2 MiB      0.0 MiB           2       await asyncio.sleep(1)
        11     25.9 MiB   -152.3 MiB           1       del b
        12     25.9 MiB      0.0 MiB           1       return a
    
  10. chr1st1ank commented on Feb 3, 2022

    @chr1st1ank

    Ok, thank you. If there is a filter on too small changes, that might be the issue. I moved the @profile one level up the call stack and now I can see some numbers. The inner functions did apparently not make enough of a difference. Still the numbers are too small now, but that might be an issue with dereferencing the complex objects which are allocated. I think I need to find something else to figure out how much memory these objects take. But thanks for the clarification.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions