1

I have some asyncio tasks and I need to pause all of them. This is my part of code:

import asyncio
import random


async def workers1():
    while True:
        k = random.randint(100, 200)
        await asyncio.sleep(k)
        await my_print(k)


async def workers2():
    while True:
        k = random.randint(100, 200)
        await asyncio.sleep(k)
        await my_print(k)


async def my_print(k):
    print(k)
    if k == 122:
        >>>>>>> suspend all of workers
        while k != 155:
            k = await repair()
            await asyncio.sleep(1)
        r>>>>>> resume all of workers

async def main():
    tasks = [asyncio.create_task(workers1()),
             asyncio.create_task(workers2())
             ]
    [await x for x in tasks]


if __name__ == '__main__':
    asyncio.run(main())

How can I suspend all of workers in my code when trouble happens in a function my_print and after repair in my_print resume all of tasks?

I will be glad if you give an example. I have been seen this link. But that's not what I need.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
  • I think you should clearly explain why [the question you linked](https://stackoverflow.com/questions/66687549/is-it-possible-to-suspend-and-restart-tasks-in-async-python) is not what you need. Is it that you need to suspend routines without wrapping the task runners? If so edit your question to say that. – Sam Hartman Jan 31 '23 at 01:11
  • @Sam Hartman - I will need to run another task while the others are sleeping – dmitry123321 Jan 31 '23 at 22:26
  • What does "`>>>>>>>`" and "`r>>>>>>`" mean? The syntax highlighter is not fond of it. – Peter Mortensen Feb 02 '23 at 03:23
  • @Peter Mortensen - these are just signs to draw attention to this part of the code – dmitry123321 Feb 02 '23 at 15:43

2 Answers2

1

Simply replace your call to await asyncio.sleep(1) with time.sleep(1). If your code doesn't have an await expression in it, all the other tasks are effectively blocked.

import asyncio
import random
import time


async def workers1():
    while True:
        k = random.randint(100, 200)
        await asyncio.sleep(k)
        await my_print(k)
        
        
async def workers2():
    while True:
        k = random.randint(100, 200)
        await asyncio.sleep(k)
        await my_print(k)
        
        
async def my_print(k):
    print(k)
    if k == 122:
        >>>>>>> suspend all of workers
        while k != 155:
            k = random.randint(100, 200)
            time.sleep(1.0)  # CHANGE HERE
        r>>>>>> resume all of workers
    
async def main():
    tasks = [asyncio.create_task(workers1()), 
             asyncio.create_task(workers2())
             ]
    [await x for x in tasks]
    
    
if __name__ == '__main__':
    asyncio.run(main())
Paul Cornelius
  • 9,245
  • 1
  • 15
  • 24
  • i know that time - is blocking but i need to run repair another task while others are sleeping, thanks bro , but it is won't work in my case – dmitry123321 Jan 31 '23 at 22:35
0

So, first, note that the time.sleep trick can be replaced with any non-asynchronous code. So you can do anything that runs synchronously instead of time.sleep. Including set up a second asyncio loop in a different thread and run tasks in that loop. The following code uses ThreadPoolExecutor from concurrent.futures to set up a new event loop. In particular:

    future = executor.submit(asyncio.run, task_3())

Will set up a new thread and run task_3 in that new loop. The next line future.result() blocks the entire first loop (task_1 and task_2) until task_3 exits. In task_3 you can do any asyncio operations you like, and until that exits all of the existing tasks will be suspended.

import asyncio, concurrent.futures

async def task_1():
    while True:
        print('task 1 runs')
        await asyncio.sleep(1)

async def task_2():
        print('task 2 starts')
        await asyncio.sleep(5)
        print('first set of tasks suspends')
        future = executor.submit(asyncio.run, task_3())
        print('suspending existing tasks')
        future.result()
        print('resuming tasks')
        

async def task_3():
    print('task 3 runs')
    await asyncio.sleep(4)
    print('task 3 finishes')

async def main():
    asyncio.ensure_future(task_1())
    asyncio.ensure_future(task_2())
    await asyncio.sleep(15)
    
executor = concurrent.futures.ThreadPoolExecutor()

asyncio.run(main())

Sam Hartman
  • 6,210
  • 3
  • 23
  • 40
  • it works great!!!!!! Thank you very much, and please tell me what to do if there are 4 tasks and only 2 specific ones need to be stopped? – dmitry123321 Feb 01 '23 at 01:34
  • 1
    If you only need to suspend some tasks you need something likke `Suspendable` from [the answer you didn't like](https://stackoverflow.com/a/66695548/2594812). Basically you need to be able to interpose something in front of the task that asks it to suspend. You might also be able to subclass Task. It's going to be a significant mess. You are better off refactoring your code and using something like asyncio.Event or asyncio.Semaphore to allow you to block a task at appropriate points. You'd need to share a lot more detail of your problem to get a goodsolution; probably another question. – Sam Hartman Feb 01 '23 at 02:51