|
@@ -0,0 +1,64 @@
|
|
|
|
+#!/usr/bin/env python3
|
|
|
|
+import asyncio
|
|
|
|
+import time
|
|
|
|
+from multiprocessing import Manager
|
|
|
|
+from queue import Empty, Queue
|
|
|
|
+from typing import Callable, Generator
|
|
|
|
+
|
|
|
|
+from nicegui import app, background_tasks, run, ui
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+class Worker:
|
|
|
|
+
|
|
|
|
+ def __init__(self) -> None:
|
|
|
|
+ self._queue: Queue
|
|
|
|
+ self.progress: float = 0.0
|
|
|
|
+ self.is_running: bool = False
|
|
|
|
+
|
|
|
|
+ app.on_startup(self._create_queue)
|
|
|
|
+
|
|
|
|
+ async def run(self, func: Callable[..., Generator[float, None, None]]) -> None:
|
|
|
|
+ background_tasks.create(run.cpu_bound(self._run_generator, func, self._queue))
|
|
|
|
+ background_tasks.create(self._consume_queue())
|
|
|
|
+
|
|
|
|
+ @staticmethod
|
|
|
|
+ def _run_generator(func: Callable[..., Generator[float, None, None]], queue: Queue) -> None:
|
|
|
|
+ for progress in func():
|
|
|
|
+ queue.put({'progress': progress})
|
|
|
|
+ queue.put({'progress': 1.0})
|
|
|
|
+
|
|
|
|
+ def _create_queue(self) -> None:
|
|
|
|
+ self._queue = Manager().Queue()
|
|
|
|
+
|
|
|
|
+ async def _consume_queue(self) -> None:
|
|
|
|
+ self.is_running = True
|
|
|
|
+ self.progress = 0.0
|
|
|
|
+ while self.progress < 1.0:
|
|
|
|
+ try:
|
|
|
|
+ msg = self._queue.get_nowait()
|
|
|
|
+ except Empty:
|
|
|
|
+ await asyncio.sleep(0.1)
|
|
|
|
+ continue
|
|
|
|
+ self.progress = msg['progress']
|
|
|
|
+ self.is_running = False
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+def heavy_computation() -> Generator[float, None, None]:
|
|
|
|
+ n = 50
|
|
|
|
+ for i in range(n):
|
|
|
|
+ time.sleep(0.1)
|
|
|
|
+ yield i / n
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+worker = Worker()
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+@ui.page('/')
|
|
|
|
+def main_page():
|
|
|
|
+ ui.button('compute', on_click=lambda: worker.run(heavy_computation))
|
|
|
|
+ ui.linear_progress().props('instant-feedback') \
|
|
|
|
+ .bind_value_from(worker, 'progress') \
|
|
|
|
+ .bind_visibility_from(worker, 'is_running')
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ui.run()
|