Issue
asyncio: Can I wrap a sync REST call in async? FTX fetch_position is a REST API call, it's not async and not awaitable. I tried below hoping if each call is 300ms, total not 300ms x3 = 900ms, but rather (wishful thinking) 300ms for all three using asyncio magic (Coorperative multi-tasking). But it didn't work. Overall took about 900ms. Am i doing something wrong here? Thanks!
async def _wrapper_fetch_position(exchange : ccxt.Exchange):
pos = exchange.fetch_positions()
return pos
import asyncio
import nest_asyncio
loop = asyncio.get_event_loop()
nest_asyncio.apply()
pos1 = loop.run_until_complete(_wrapper_fetch_position(exchange1))
pos2 = loop.run_until_complete(_wrapper_fetch_position(exchange2))
pos3 = loop.run_until_complete(_wrapper_fetch_position(exchange3))
Solution
Directly, no, you'll block the event loop and won't get concurrency. However, you can use multithreading with asyncio, wrapping sync calls in a thread with asyncio's to_thread
coroutine. This delegates a blocking function to run in a separate thread backed by a ThreadPoolExecutor
and returns an awaitable, so you can use it in await expressions just like it was non-blocking. Here is an example with the requests
library to make 20 web requests, comparing synchronous with threads:
import asyncio
import time
import requests
def in_sequence():
for i in range(20):
requests.get('https://www.example.com')
async def with_threads():
def make_request(): requests.get('https://www.example.com')
reqs = [asyncio.to_thread(make_request) for _ in range(20)]
await asyncio.gather(*reqs)
async def main():
sequence_start = time.time()
in_sequence()
sequence_end = time.time()
print(f'In sequence {sequence_end - sequence_start}')
thread_start = time.time()
await with_threads()
thread_end = time.time()
print(f'With threads {thread_end - thread_start}')
asyncio.run(main())
Running this on my machine, I get the following results, demonstrating the performance difference:
In sequence 1.9963197708129883
With threads 0.26117658615112305
If you want more control over the thread pool, you can manually create one and use asyncio's loop.run_in_executor method. See https://docs.python.org/3/library/asyncio-eventloop.html#asyncio.loop.run_in_executor for more details and an example on how to use this.
Answered By - Matt Fowler
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.