Closed cgabriel5 closed 4 years ago
In short, you should use app.processEvents()
This is because nigui has its own event loop and threadproxy also has its own event loop.
app.run()
is like
while true:
app.processEvents()
app.run
will block the main thread. And after you close the application window, run() break and then run proxy.process() and that is why you see console output after you closed the window.
If you only need to process the events coming from nigui e.g. mouse clicks, closing windows... then calling app.run()
is enough.
However as mentioned before threadproxy has its own event loop. You have to call proxy.process()
to process one event or proxy.poll()
and then start nim async event loop runForever()
.
This part of code fuses the event loop of both nigui and threadproxy.
while true:
app.processEvents()
while proxy.process():
discard
sleep 16
Yeah, I suspected app.run()
was blocking ThreadProxy. WebGui doesn't have something similar to nigui's app.processEvents()
, so I need to figure out a way to fuse WebGui's and ThreadProxy's event loops. Thank you for taking the time to reply.
Hello @jackhftang. I'm currently building a GUI application (a package manager) and need a way to perform time consuming operations without freezing the main thread. While searching the Web I found this post where the OP was also in a similar situation. After reading your reply, ThreadProxy seems to be the missing link to perform said operations (i.e. updating/downloading packages) without blocking the main thread. In my case, I'm having trouble getting ThreadProxy working with WebGui.
The following are examples of nigui/webgui with threadproxy:
nigui
Working Example (Both future callbacks run)```nim import os, nigui, threadproxy proc workerMain(proxy: ThreadProxy) {.thread.} = proxy.onData "task1": let n = data.getInt() sleep n result = %"ThreadProxy Value" waitFor proxy.poll() proc main() = let proxy = newMainThreadProxy("main") proxy.createThread("worker", workerMain) app.init() var window = newWindow("Win") window.width = 600.scaleToDpi window.height = 400.scaleToDpi var container = newLayoutContainer(Layout_Vertical) window.add(container) var button = newButton("Start") var textArea = newTextArea() container.add(button) container.add(textArea) proc dummy_future(): Future[string] = var retFuture = newFuture[string]("dummy_future") sleep(1000) retFuture.complete("Future Value") return retFuture proc foo() = var fut = proxy.ask("worker", "task1", %1000) fut.addCallback( proc () = echo "[FutureValue]: ", fut.read ) var f = dummy_future() f.addCallback( proc () = echo "[FutureValue]: ", f.read ) foo() window.show() while true: app.processEvents() while proxy.process(): discard sleep 16 main() ``` The above code gives the expected output: ``` [FutureValue]: Future Value [FutureValue]: "ThreadProxy Value" ```
nigui
Non-Working Example (ThreadProxy future callback never runs)```nim import os, nigui, threadproxy proc workerMain(proxy: ThreadProxy) {.thread.} = proxy.onData "task1": let n = data.getInt() sleep n result = %"ThreadProxy Value" waitFor proxy.poll() proc main() = let proxy = newMainThreadProxy("main") proxy.createThread("worker", workerMain) app.init() var window = newWindow("Win") window.width = 600.scaleToDpi window.height = 400.scaleToDpi var container = newLayoutContainer(Layout_Vertical) window.add(container) var button = newButton("Start") var textArea = newTextArea() container.add(button) container.add(textArea) proc dummy_future(): Future[string] = var retFuture = newFuture[string]("dummy_future") sleep(1000) retFuture.complete("Future Value") return retFuture proc foo() = var fut = proxy.ask("worker", "task1", %1000) fut.addCallback( # <-------------- Never runs. proc () = echo "[FutureValue]: ", fut.read ) var f = dummy_future() f.addCallback( proc () = echo "[FutureValue]: ", f.read ) foo() window.show() while true: app.run() while proxy.process(): discard sleep 16 main() ``` `proxy.ask` future callback never runs so the output is only: ``` [FutureValue]: Future Value ```
webgui
Non-Working Example (ThreadProxy future callback never runs)```nim import os, webgui, threadproxy proc workerMain(proxy: ThreadProxy) {.thread.} = proxy.onData "task1": let n = data.getInt() sleep n result = %"ThreadProxy Value" waitFor proxy.poll() proc main() = let proxy = newMainThreadProxy("main") proxy.createThread("worker", workerMain) let app = newWebView(""" """ ) proc dummy_future(): Future[string] = var retFuture = newFuture[string]("dummy_future") sleep(1000) retFuture.complete("Future Value") return retFuture proc foo() = var fut = proxy.ask("worker", "task1", %1000) fut.addCallback( # <-------------- Never runs until after application window is closed. proc () = echo "[FutureValue]: ", fut.read ) var f = dummy_future() f.addCallback( proc () = echo "[FutureValue]: ", f.read ) foo() # This does not seem right... while true: app.run() while proxy.process(): discard sleep 16 app.exit() main() ``` `proxy.ask` future callback never runs so the output is only: ``` [FutureValue]: Future Value ```
In short, the ThreadProxy
proxy.ask
future callback does not run in the WebGui example. It's almost as it if hangs because once the application window closes the callback finally runs.Looking more into your reply (nigui example) I noticed you used
app.processEvents()
instead ofapp.run()
. This change is the difference between the working and non-working nigui examples. Where the working example usesapp.processEvents()
. This is interesting because all nigui examples make use ofapp.run()
. When it comes to WebGui, I don't see something akin to nigui'sapp.processEvents()
, which is where I think the issue lies.ThreadProxy is a really cool idea to leverage threads but since I'm new to async/futures/threads in Nim I'm having trouble implementing it with WebGui. Which is why I thought I'd reach out. If you could give me your insight here to get ThreadProxy running alongside WebGui, if at all possible, it would be much appreciated. Thank you.
Miscellaneous:
nim compile -r -d:release -d:danger --threads:on --forceBuild:on file.nim
.1.4.0
,1.2.6
,1.2.2
, and1.2.0
.threadproxy
,nigui
,webgui
packages.Ubuntu 16.04
.