main.py 1.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364
  1. #!/usr/bin/env python3
  2. import asyncio
  3. import time
  4. from multiprocessing import Manager
  5. from queue import Empty, Queue
  6. from typing import Callable, Generator
  7. from nicegui import app, background_tasks, run, ui
  8. class Worker:
  9. def __init__(self) -> None:
  10. self._queue: Queue
  11. self.progress: float = 0.0
  12. self.is_running: bool = False
  13. app.on_startup(self._create_queue)
  14. async def run(self, func: Callable[..., Generator[float, None, None]]) -> None:
  15. background_tasks.create(run.cpu_bound(self._run_generator, func, self._queue))
  16. background_tasks.create(self._consume_queue())
  17. @staticmethod
  18. def _run_generator(func: Callable[..., Generator[float, None, None]], queue: Queue) -> None:
  19. for progress in func():
  20. queue.put({'progress': progress})
  21. queue.put({'progress': 1.0})
  22. def _create_queue(self) -> None:
  23. self._queue = Manager().Queue()
  24. async def _consume_queue(self) -> None:
  25. self.is_running = True
  26. self.progress = 0.0
  27. while self.progress < 1.0:
  28. try:
  29. msg = self._queue.get_nowait()
  30. except Empty:
  31. await asyncio.sleep(0.1)
  32. continue
  33. self.progress = msg['progress']
  34. self.is_running = False
  35. def heavy_computation() -> Generator[float, None, None]:
  36. n = 50
  37. for i in range(n):
  38. time.sleep(0.1)
  39. yield i / n
  40. worker = Worker()
  41. @ui.page('/')
  42. def main_page():
  43. ui.button('compute', on_click=lambda: worker.run(heavy_computation))
  44. ui.linear_progress().props('instant-feedback') \
  45. .bind_value_from(worker, 'progress') \
  46. .bind_visibility_from(worker, 'is_running')
  47. ui.run()