The async with statement will wait before the unlock call, and unlock will also wait until the async with statement exits. If you use unlock in coroutine A and async with in coroutine B, the execution order will be: the part before the unlock call → the part in async with → the part after the unlock call. This is much more convenient than using Events repeatedly.
Just a technical suggestion: We can’t call it a synchronization primitive because it makes use of existing synchronization primitives. I would suggest calling it a ‘Task Coordinator.’
I agree that this isn’t a primitive; your entire purpose here is to use existing primitives to make something that’s easier to use. What I’m less clear on is the conceptual meaning here, and why it’s called a “Key”. Can you elaborate?
Because it behaves like a default locked lock, it will block the code in async with, which is similar to the behavior of Lock. However, a “key” is needed to unlock the statements in Async with, and the key cannot be pulled out before async with is executed (it will be blocked). This behavior is like a real key
So far you’ve only proposed a new class, but have not explained how this will improve code (e.g. which code patterns will get clearer with the new functionality, ideally by pointing to real(fistic) code instead of toy examples).
I think this is useful in one-to-one or one-to-many collaborative coroutines, as it can stipulate that the async withcode block must be fully executed when unlock is called. If you don’t use this method, you have to set an Event at the start and an Event at the end, and you can’t intuitively see where it starts and ends. To ensure that it ends when an exception occurs, you have to use try... except... This is tantamount to adding insult to injury for the already complex asynchronous programming.
This is where I’m going to use this new synchronization method. I had to shorten it because the code was too long.
import asyncio,httpx
client = httpx.AsyncClient()
url = 'example.com'
file =None
class Key:
...
async def download_block(start_pos,save_info = None):
headers =#build requests headers
async with client.stream('GET',url,headers=headers) as re:
if save_info is not None:
re_header = re.headers
await save_info.unlock()#async with must wait for unlock(), and unlock() will also wait for async with to complete
async for i in re.aiter_raw():
file.seek_and_write(i)
async def download_main(url):
save_info = Key()
asyncio.create_task(download_block(0,save_info))
async with save_info:
#get file_size,file_name,ableToParallelDownload from re_head
file = open(filename,'w+b')
if ableToParallelDownload:
#create more download_block task,and end the task at the appropriate time
asyncio.run(download_main(url))