Skip to content

Instantly share code, notes, and snippets.

@internetimagery
Last active June 3, 2021 01:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save internetimagery/d7a7dc8712bc191a584d8a73aee9ca54 to your computer and use it in GitHub Desktop.
Save internetimagery/d7a7dc8712bc191a584d8a73aee9ca54 to your computer and use it in GitHub Desktop.
Run async code in sync (helpful for piecemeal conversion to async within codebase)
from concurrent.futures import ThreadPoolExecutor
import asyncio
def run_sync(task):
try:
loop = asyncio.get_event_loop()
except RuntimeError:
loop = None
if not loop or loop.is_running():
with ThreadPoolExecutor(1) as pool:
return pool.submit(asyncio.run, task).result()
else:
return loop.run_until_complete(task)
if __name__ == "__main__":
async def func1(num):
return num + 1
async def func2(num):
return run_sync(func1(num+1))
def func3(num):
return run_sync(func2(num+1))
async def func4(num):
return func3(num+1)
def main(num):
return run_sync(func4(num+1))
assert main(0) == 5
from concurrent.futures import ThreadPoolExecutor
import asyncio
import threading
import atexit
_worker_thread = None
_worker_loop = None
def shutdown():
def close():
if any(
task
for task in asyncio.Task.all_tasks()
if task != asyncio.Task.current_task() and not task.done()
):
_worker_loop.call_soon(close)
else:
_worker_loop.stop()
_worker_loop.call_soon_threadsafe(close)
_worker_thread.join()
def run_in_worker(task):
global _worker_thread, _worker_loop
if not _worker_thread:
# Build base worker
def bootstrap(loop):
asyncio.set_event_loop(loop)
try:
loop.run_forever()
finally:
loop.close()
_worker_loop = asyncio.new_event_loop()
_worker_thread = threading.Thread(target=bootstrap, args=(_worker_loop,))
_worker_thread.setDaemon(True)
_worker_thread.start()
atexit.register(shutdown)
if threading.current_thread() == threading.main_thread():
return asyncio.run_coroutine_threadsafe(task, _worker_loop)
with ThreadPoolExecutor(1) as pool:
return pool.submit(asyncio.run, task)
if __name__ == "__main__":
async def func1(num):
return num + 1
async def func2(num):
return run_in_worker(func1(num+1)).result()
def func3(num):
return run_in_worker(func2(num+1)).result()
async def func4(num):
return func3(num+1)
def main(num):
return run_in_worker(func4(num+1)).result()
print(">>", main(0))
assert main(0) == 5
async def test():
print("HERE")
await asyncio.sleep(1)
print("STILL HERE")
run_in_worker(test())
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment