This is an interesting situation I have come across. I wrote some code a while back that was synchronous but then I switched to async. The following code resembles the async code.
async def some_coroutine(args, obj):
genarg1, genarg2 = args
for (param1, param2) in some_generator(genarg1, genarg2):
await asyncio.sleep(0) # do this to prevent blocking and give control to event loop
# do work
for i in enumerate(param2):
await asyncio.sleep(0) # do this to prevent blocking and give control to event loop
obj.somefunc(i, param1)
pass
I want to refactor the above such that I can make it compatible with some of the non-async code. I used to have it where the for loops can be called in their own functions except this would block the eventloop. I don't want them to take over the event loop without giving control back to the event loop from time to time. I'd like to refactor to something like this but can't figure out how to avoid the blocking aspect of it:
async def some_coroutine(args, obj):
genarg1, genarg2 = args
somefunc(genarg1, genarg2, obj)
def somefunc(genarg1, genarg2, obj):
for (param1, param2) in some_generator(genarg1, genarg2):
# do work
for i in enumerate(param2):
obj.somefunc(i, param1)
pass
Clearly, the first code block, the protocol attempted to not block the event loop because the code was in one routine and had await asyncio.sleep(0)
. But now the refactored code breaks apart the for loop and is blocking and I'm not able to place await asyncio.sleep(0)
in somefunc. I'd like to refactor the code this way so I could call it from other functions that don't use eventloops (e.g., test cases) but when an eventloop is used, I'd prefer it to be versatile enough to not block it.
Is this possible or am I just thinking about it wrong (i.e., refactor the code differently)?