В моем случае это один объект сеанса, подключающийся к веб-сайту, и каждый контекст будет текущей учетной записью, подключенной к веб-сайту. В качестве системного ограничения - никакие две учетные записи не могут быть подключены одновременно, а подключение является дорогостоящей операцией.
Я разработал следующий механизм, который предполагает отпускание контекста (переключение аккаунт) во время дорогостоящих фоновых операций:
Код: Выделить всё
counter = 0 # i.e. ContextVar for current account
def increase_counter():
global counter
counter += 1
def decrease_counter():
global counter
counter -= 1
async def run_operation():
while True:
operation = operation_queue.get()
increase_counter()
task = asyncio.create_task(operation())
task.add_done_callback(lambda fut: decrease_counter())
await wait_for_free() # wait until counter == 0
switch_context() # Log in to a different account
async def operation():
# do stuff
decrease_counter()
sleep(60) # Long background operation
await wait_for_context() # Wait for context to come back and be 1.
# continue
К сожалению, когда одновременно выполняются две операции, он перестает работать:
Код: Выделить всё
async def operation():
increase_counter()
task1 = asyncio.create_task(sub_op())
task1.add_done_callback(decrease)
increase_counter()
task2 = asyncio.create_task(sub_op())
task2.add_done_callback(decrease)
decrease_counter()
await asyncio.gather(task1, task2)
await wait_for_context()
async def sub_op():
decrease_counter()
sleep(60)
await wait_for_context()
Код: Выделить всё
run_op (+1 = 1)
task1_creation (+1 = 2)
task2_creation (+1 = 3)
gather_release (-1 = 2)
task1_sleep (-1 = 1)
task2_sleep (-1 = 0) # Context released
task1_resume (+1 = 1)
task2_resume (+1 = 2)
task1_done_callback (-1 = 1)
task2_done_callback (-1 = 0) # Context needlessly released
gather_resume (+1 = 1)
Подробнее здесь: https://stackoverflow.com/questions/790 ... in-asyncio
Мобильная версия