Skip to content

Instantly share code, notes, and snippets.

@wonderbeyond
Forked from konpatp/async.py
Last active November 23, 2022 01:04
Show Gist options
  • Select an option

  • Save wonderbeyond/f2eb849d1e5f024a88508b60db376b49 to your computer and use it in GitHub Desktop.

Select an option

Save wonderbeyond/f2eb849d1e5f024a88508b60db376b49 to your computer and use it in GitHub Desktop.

Revisions

  1. wonderbeyond revised this gist Nov 23, 2022. 1 changed file with 12 additions and 6 deletions.
    18 changes: 12 additions & 6 deletions async.py
    Original file line number Diff line number Diff line change
    @@ -2,12 +2,22 @@
    import asyncio


    def get_event_loop():
    try:
    return asyncio.get_event_loop()
    except RuntimeError as e:
    if "There is no current event loop in thread" in str(e):
    loop = asyncio.new_event_loop()
    asyncio.set_event_loop(loop)
    return asyncio.get_event_loop()
    raise


    def force_async(fn):
    '''
    turns a sync function to async function using threads
    '''
    from concurrent.futures import ThreadPoolExecutor
    import asyncio
    pool = ThreadPoolExecutor()

    @wraps(fn)
    @@ -22,13 +32,9 @@ def force_sync(fn):
    '''
    turn an async function to sync function
    '''
    if not hasattr(force_sync, '_event_loop'):
    force_sync._event_loop = asyncio.new_event_loop()
    loop = force_sync._event_loop

    @wraps(fn)
    def wrapper(*args, **kwargs):
    res = fn(*args, **kwargs)
    return loop.run_until_complete(res) if asyncio.iscoroutine(res) else res
    return get_event_loop().run_until_complete(res) if asyncio.iscoroutine(res) else res

    return wrapper
  2. wonderbeyond revised this gist Nov 22, 2022. 1 changed file with 8 additions and 7 deletions.
    15 changes: 8 additions & 7 deletions async.py
    Original file line number Diff line number Diff line change
    @@ -1,4 +1,5 @@
    import functools
    from functools import wraps
    import asyncio


    def force_async(fn):
    @@ -9,7 +10,7 @@ def force_async(fn):
    import asyncio
    pool = ThreadPoolExecutor()

    @functools.wraps(fn)
    @wraps(fn)
    def wrapper(*args, **kwargs):
    future = pool.submit(fn, *args, **kwargs)
    return asyncio.wrap_future(future) # make it awaitable
    @@ -21,13 +22,13 @@ def force_sync(fn):
    '''
    turn an async function to sync function
    '''
    import asyncio
    if not hasattr(force_sync, '_event_loop'):
    force_sync._event_loop = asyncio.new_event_loop()
    loop = force_sync._event_loop

    @functools.wraps(fn)
    @wraps(fn)
    def wrapper(*args, **kwargs):
    res = fn(*args, **kwargs)
    if asyncio.iscoroutine(res):
    return asyncio.get_event_loop().run_until_complete(res)
    return res
    return loop.run_until_complete(res) if asyncio.iscoroutine(res) else res

    return wrapper
  3. @konpatp konpatp revised this gist Feb 3, 2017. 1 changed file with 3 additions and 2 deletions.
    5 changes: 3 additions & 2 deletions test.py
    Original file line number Diff line number Diff line change
    @@ -30,15 +30,16 @@ def test():
    @force_sync
    async def main():
    import asyncio
    # if it were to execute sequentially, it would take 10 seconds, in this case we expect to see only 1 second
    futures = list(map(lambda x: test(),
    range(10)))
    return await asyncio.gather(*futures)

    import time

    # take the elapsed time
    start = time.time()
    res = main()
    end = time.time()
    elapsed = end - start
    self.assertEqual(len(res), 10)
    self.assertLess(elapsed, 1.2)
    self.assertLess(elapsed, 1.2) # a little more than 1 second is normal
  4. @konpatp konpatp revised this gist Feb 3, 2017. 1 changed file with 44 additions and 11 deletions.
    55 changes: 44 additions & 11 deletions test.py
    Original file line number Diff line number Diff line change
    @@ -1,11 +1,44 @@
    @force_async
    def long_blocking_function():
    import time
    time.sleep(10)
    return True

    import asyncio
    async def run():
    a = long_blocking_function()
    b = long_blocking_function()
    return await asyncio.gather(a, b) # [True, True] in 10 seconds
    import unittest
    from async import *

    class AsyncCanTurnAsyncIntoSyncFunction(unittest.TestCase):
    def test_turn_async_to_sync(self):
    @force_sync
    async def test():
    import asyncio
    await asyncio.sleep(0.1)
    return 1 + 2

    self.assertEqual(test(), 3)

    def test_turn_sync_to_sync(self):
    @force_sync
    def test():
    return 1 + 2

    self.assertEqual(test(), 3)


    class AsyncCanTurnSyncIntoAsyncFunction(unittest.TestCase):
    def test_turn_sync_to_async(self):
    @force_async
    def test():
    import time
    time.sleep(1)
    return True

    @force_sync
    async def main():
    import asyncio
    futures = list(map(lambda x: test(),
    range(10)))
    return await asyncio.gather(*futures)

    import time

    start = time.time()
    res = main()
    end = time.time()
    elapsed = end - start
    self.assertEqual(len(res), 10)
    self.assertLess(elapsed, 1.2)
  5. @konpatp konpatp revised this gist Feb 3, 2017. 1 changed file with 26 additions and 3 deletions.
    29 changes: 26 additions & 3 deletions async.py
    Original file line number Diff line number Diff line change
    @@ -1,10 +1,33 @@
    def async(fn):
    import functools


    def force_async(fn):
    '''
    turns a sync function to async function using threads
    '''
    from concurrent.futures import ThreadPoolExecutor
    import asyncio
    pool = ThreadPoolExecutor()

    def wrapper(*args, **kwargs) -> asyncio.Future:
    @functools.wraps(fn)
    def wrapper(*args, **kwargs):
    future = pool.submit(fn, *args, **kwargs)
    return asyncio.wrap_future(future) # make it awaitable

    return wrapper
    return wrapper


    def force_sync(fn):
    '''
    turn an async function to sync function
    '''
    import asyncio

    @functools.wraps(fn)
    def wrapper(*args, **kwargs):
    res = fn(*args, **kwargs)
    if asyncio.iscoroutine(res):
    return asyncio.get_event_loop().run_until_complete(res)
    return res

    return wrapper
  6. @konpatp konpatp revised this gist Feb 3, 2017. 1 changed file with 11 additions and 0 deletions.
    11 changes: 11 additions & 0 deletions test.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,11 @@
    @force_async
    def long_blocking_function():
    import time
    time.sleep(10)
    return True

    import asyncio
    async def run():
    a = long_blocking_function()
    b = long_blocking_function()
    return await asyncio.gather(a, b) # [True, True] in 10 seconds
  7. @konpatp konpatp created this gist Feb 3, 2017.
    10 changes: 10 additions & 0 deletions async.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,10 @@
    def async(fn):
    from concurrent.futures import ThreadPoolExecutor
    import asyncio
    pool = ThreadPoolExecutor()

    def wrapper(*args, **kwargs) -> asyncio.Future:
    future = pool.submit(fn, *args, **kwargs)
    return asyncio.wrap_future(future) # make it awaitable

    return wrapper