0

Here is my code:

async def runTaskWrapped(options):
    layoutz = [[sg.Text("Running...", key="runstatus")]];
    windowz = sg.Window("New Task", layoutz);
    x = threading.Thread(target=runTask, args=(options,));
    x.start();
    startTime = time.time();
    while True:
        eventz, valuesz = windowz.read(timeout=100)
        if eventz == sg.WIN_CLOSED:
            if x.is_alive():
                continue
            break
        if x.is_alive() == False:
            x.join()
            windowz.FindElement('runstatus').Update(value='Done! Check the new log.txt for more info.');
            break;
        else:
            windowz.FindElement('runstatus').Update(value='Running... (' + str(math.floor(time.time()-startTime)) + ')')

asyncio.run(runTaskWrapped(options));

I have tried everything and it still seems that execution pauses after asyncio.run(runTaskWrapped(options));

Any idea why this may be?

EDIT: I tried threading.Thread, and although it didn't pause execution, pysimplegui (imported as sg) didnt do anything and no window showed up for it like it does when called synchronously.

I tried trio too, but trio paused execution. trio.run(runTaskWrapped, options);

Wasabi Thumbs
  • 303
  • 1
  • 2
  • 8
  • ...That's not how asyncio works. asyncio's sole purpose is to respond to multiple network sockets simultaneously from a single thread. If your program does not communicate with the network, you have no need for asyncio. Further, unless there is at least one `await` expression inside the body of your `async def` funciton, there is no difference between delcaring it `async def` and calling it with `asyncio.run()` and not declaring it `async` and invoking it directly. If you want to run that without interrupting program flow, declare it as non-async and create a new thread running it. – wallefan Jun 26 '20 at 23:22
  • I tried running it with threading.Thread and that also paused execution, thats why i looked into async for python, and asyncio is what came up @wafflefan – Wasabi Thumbs Jun 26 '20 at 23:28
  • Correction- it didn't pause execution, but pysimplegui stopped working. – Wasabi Thumbs Jun 26 '20 at 23:30
  • What do you mean by "paused execution"? Can you show me the rest of your code please? – wallefan Jun 26 '20 at 23:30
  • I run `threading.Thread(target=runTaskWrapped, args=(options,));` and pysimplegui (imported as sg) does nothing, no window shows up like it does when called synchronously – Wasabi Thumbs Jun 26 '20 at 23:32
  • I'm assuming you started the thread after creating it? – wallefan Jun 26 '20 at 23:45
  • @wallefan holy shit im dumb as bricks – Wasabi Thumbs Jun 27 '20 at 01:06
  • You cannot run tkinter code in a thread. You can't make tkinter calls of any kind from a thread. It's not a thread-safe library. It has to be run as the "mainthread". There is a PySimpleGUI program someone wrote that uses async. https://github.com/nngogol/async-desktop-chat. There are a number of demo programs posted that show how to use threads with PySimpleGUI. You just can't have PySimpleGUI be a in thread. – Mike from PSG Jun 27 '20 at 09:11

1 Answers1

3

When you call asyncio.run(some_function()), your program will not go to the next line until some_function() returns. In your case, runTaskWrapped doesn't return until you execute one of its "break" statements.

We deal with this sort of thing all the time. If you call any function f(), your program won't continue until f() returns. That's a familiar concept.

What's different about asyncio is that it creates a loop of its own, called the event loop, and launches some_function() from inside that loop. That allows you to start other tasks from within some_function(), and those other tasks get a chance to execute when some_function() encounters an "await" statement. That's a powerful concept if that's what you need. But it's only useful if you have two or more tasks that need to wait on external resources, like a network or a serial communications link, and one of the tasks can proceed while the other is waiting.

Your function runTaskWrapped does not contain any "await" statements. So asyncio creates an event loop, hands control to runTaskWrapped. That's a blind alley. It is more-or-less an infinite loop and doesn't "await" anything. Therefore there is no way out of runTaskWrapped, and your program is effectively dead at that point.

In order to make use of asyncio you must structure your program to have more than one task containing "await"s.

You are writing a GUI program, which typically means that it already has an event loop of its own. In some cases it is possible to run the GUI's event loop and the asyncio event loop together, but unless you have a specific need to do this it doesn't gain you anything.

You are also trying to use asyncio with multiple threads, and although this is possible it needs to be done quite carefully. You can start other threads just as in any other Python program, but the presence of those other threads doesn't change what happens in your main thread. You must specifically write code to synchronize events between threads.

No matter what you do in those other threads, asyncio.run(some_function()) will not return until its argument is finished.

Paul Cornelius
  • 9,245
  • 1
  • 15
  • 24