1

I have a queue variable and an input order. In case the queue has something, I have to force the input order to stop. I have had to use asyncio module to do that. As a example, let's see the following code:

import asyncio
import multiprocessing
import time
from aioconsole import ainput


def my_function(queue):
    time.sleep(3)
    queue.put(5)


async def my_loop(queue):
    while True:
        await asyncio.sleep(0.1)
        if not queue.empty():
            break


async def main():
    queue = multiprocessing.Queue()
    p = multiprocessing.Process(target=my_function, args=(queue,))
    p.start()
    task1 = asyncio.create_task(ainput("Enter text:"))
    task2 = asyncio.create_task(my_loop(queue))
    await asyncio.wait([task1, task2], return_when='FIRST_COMPLETED')
    try:
        text = task1.result()
        q = ""
    except asyncio.exceptions.InvalidStateError:
        text = ""
        q = queue.get()
    print('Doing stuff with input %s/%s...' % (text, q))

This works perfectly and the program ends whenever the queue has something on it or the user inputs some text. My real program has several input orders like this in a row, something like this:

import asyncio
import multiprocessing
import time
from aioconsole import ainput


def my_function(queue):
    time.sleep(3)
    queue.put(5)


async def my_loop(queue):
    while True:
        await asyncio.sleep(0.1)
        if not queue.empty():
            break


async def main():
    queue = multiprocessing.Queue()
    p = multiprocessing.Process(target=my_function, args=(queue,))
    p.start()
    task1 = asyncio.create_task(ainput("Enter text:"))
    task2 = asyncio.create_task(my_loop(queue))
    await asyncio.wait([task1, task2], return_when='FIRST_COMPLETED')
    try:
        text = task1.result()
        q = ""
    except asyncio.exceptions.InvalidStateError:
        text = ""
        q = queue.get()
    print('Doing stuff with input %s/%s...' % (text, q))


    task1 = asyncio.create_task(ainput("Next: "))
    task2 = asyncio.create_task(my_loop(queue))
    await asyncio.wait([task1, task2], return_when='FIRST_COMPLETED')

    try:
        text = task1.result()
        q = ""
    except asyncio.exceptions.InvalidStateError:
        text = ""
        q = queue.get()
    print('Doing stuff with input %s/%s...' % (text, q))


    

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

The problem is that, if I wait for the queue the first time, the second time, I have to enter the input twice, like if the first input was still waiting or something. Do you know how can I definitely "break" the first input if the user doesn't write anything? Thanks in advance

  • Can I ask a higher level question? What is it that you are trying to do? The goal of your code isn't really clear. What is the queue for? – Frank Yellin May 24 '22 at 01:26
  • The code is much more complex than that but the app receives info from the brain through an EEG, and there are many processes simultaneously. The input is there to pause or stop the app and the queue is the shared memory between processes, which in case of having something must break the input order. It's a bit difficult to explain but the thing is that it needs several inputs like this one in a row, and they have to be broken in case the queue has something – María Jaramillo Sojo May 24 '22 at 06:12

1 Answers1

0

If I understand you correctly, you can use use task.cancel() between the steps cancel all pending tasks:

import asyncio
import multiprocessing
import time
from aioconsole import ainput


def my_function(queue):
    time.sleep(3)
    queue.put(5)


async def my_loop(queue):
    while True:
        await asyncio.sleep(0.1)
        if not queue.empty():
            break


async def main():
    queue = multiprocessing.Queue()
    p = multiprocessing.Process(target=my_function, args=(queue,))
    p.start()

    task1 = asyncio.create_task(ainput("Enter text:"))
    task2 = asyncio.create_task(my_loop(queue))
    tasks = [task1, task2]

    await asyncio.wait(tasks, return_when="FIRST_COMPLETED")
    try:
        text = task1.result()
        q = ""
    except asyncio.exceptions.InvalidStateError:
        text = ""
        q = queue.get()

    print()
    print("1. Doing stuff with input %s/%s..." % (text, q))

    # cancel all tasks:
    for t in [task1, task2]:
        t.cancel()

    # Wait until all worker tasks are cancelled:
    await asyncio.gather(*tasks, return_exceptions=True)

    task1 = asyncio.create_task(ainput("Next: "))
    task2 = asyncio.create_task(my_loop(queue))
    tasks = [task1, task2]

    await asyncio.wait(tasks, return_when="FIRST_COMPLETED")

    try:
        text = task1.result()
        q = ""
    except asyncio.exceptions.InvalidStateError:
        text = ""
        q = queue.get()

    print()
    print("2. Doing stuff with input %s/%s..." % (text, q))


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

Prints (for example):

Enter text:
1. Doing stuff with input /5...
Next: Hello World

2. Doing stuff with input Hello World/...
Andrej Kesely
  • 168,389
  • 15
  • 48
  • 91
  • Thank you, but the problem remains. If I wait for the queue the first time, in the second input the user has to enter something twice – María Jaramillo Sojo May 24 '22 at 06:10
  • Anyway, your output looks good. In my case, whenever I run your code, the second time I have to input something twice if I wait for the queue the first time – María Jaramillo Sojo May 24 '22 at 07:09
  • @MaríaJaramilloSojo Without seeing the real code is hard to tell what is happening. I cannot replicate the situation now. – Andrej Kesely May 24 '22 at 07:11
  • 1
    I have literally copied your code into another script and I get the same behavior error. My code has more than a thousand lines and it is so difficult to sum up the key part in an easier script, for there are may things going on at the same time. If I knew how to solve the error I get with your code, I could extrapolate it to mine. Thank you very much for your time – María Jaramillo Sojo May 24 '22 at 07:32