Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Completion of concurrent tasks after run_forever. #55

Closed
draustin opened this issue Sep 7, 2021 · 2 comments
Closed

Completion of concurrent tasks after run_forever. #55

draustin opened this issue Sep 7, 2021 · 2 comments

Comments

@draustin
Copy link

draustin commented Sep 7, 2021

It seems that run_forever has the effect of calling QApplication.exec() while simultaneously running the event loop tasks. When exec returns, the event loop stops and run_forever returns. At this point I would like to send a stop signal to the other tasks to perform cleanup actions, and then restart the loop and run it until the tasks are complete. I came up with a solution, pasted below. This issue is a suggestion to elaborate the docstring / add an example, and to help others.

Thanks for your work.

import sys

from PyQt5 import QtWidgets
import qasync
import asyncio


class Widget(QtWidgets.QWidget):
    """A widget with a single label."""

    def __init__(self):
        QtWidgets.QWidget.__init__(self)

        self._label = QtWidgets.QLabel()
        b0 = QtWidgets.QHBoxLayout()
        self.setLayout(b0)
        b0.addWidget(self._label)

    def set_text(self, text):
        """Set the text of the label."""
        self._label.setText(text)


stop_flag = False


async def start_counting(widget):
    try:
        n = 0
        while not stop_flag:
            widget.set_text(str(n))
            await asyncio.sleep(1)
            n += 1
        print('Counting stopped.')
    except BaseException as e:
        print('Counting cancelled.')


app = QtWidgets.QApplication(sys.argv)
widget = Widget()
widget.show()
loop = qasync.QEventLoop(app)
task = loop.create_task(start_counting(widget))
# Runs until last widget closed, like QApplication.exec().
loop.run_forever()
assert not loop.is_running()
# Looking at the __init__.py in qasync, it seems that it stopped running because QApplication.exec() returned.
# However, our counting task is incomplete.
tasks = asyncio.all_tasks()
assert len(tasks) == 1

# Send stop signal. Alternative, can cancel.
stop_flag = True
# task.cancel()

# Restart the loop to finish the tasks. In this example there is only one, but gather them for generality.
gathered = asyncio.gather(*tasks)
loop.run_until_complete(gathered)

# The following does not work.
# loop.run_forever()

print('All done.')
@draustin
Copy link
Author

draustin commented Sep 7, 2021

PS this is possible related to #35.

@hosaka
Copy link
Collaborator

hosaka commented Apr 11, 2023

See my comment on #35 (comment)

@hosaka hosaka closed this as completed Apr 11, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants