Re: How to turn thread spawn call into an async call [redux; Nim 1.0.0]
Not yet AFAIK. We're still waiting on @rayman22201's patches to be finalised.
How to turn thread spawn call into an async call [redux; Nim 1.0.0]
Hi, I've been using a macro to turn thread spawn into an async call that had been [shared previously](https://forum.nim-lang.org/t/3648#22852) on this forum. With Nim 1.0.0 and improvements to asyncdispatch, I'm wondering if this capability made its way into the standard library yet? Sorry if I missed it, I browsed the async* documentation today but couldn't find anything similar. Thanks!
Re: How to turn thread spawn call into an async call
It works finally. To make the {.async.} works in quoted code, the 'await' and Future variable must be ident!! type Result* = ref object of RootObj body*: string proc waitEvent(evt: AsyncEvent): Future[void] = var fut = newFuture[void]("callAsync") addEvent(evt, (fd: AsyncFD) => (fut.complete(); true)) return fut macro callAsync(p: untyped): untyped = let await = ident("await") let fut = ident("fut") quote do: block: proc callp(evt: AsyncEvent): Result = let v = `p` evt.trigger() v proc async_call(): Future[Result] {.async.} = let evt = newAsyncEvent() let `fut` = waitEvent(evt) let val = spawn callp(evt) `await` `fut` return ^val async_call() proc ff1(v: int): Result = echo "work ", v sleep(1000) Result(body: "hello " & $v) proc ff2(v1, v2: int): Result = echo "work ", v1, " ", v2 sleep(1000) Result(body: "hello " & $v1 & " " & $v2) when isMainModule: block: let val = waitFor callAsync(ff1(1)) print "future return", val.body block: let val = waitFor callAsync(ff2(1, 2)) print "future return", val.body
Re: How to turn thread spawn call into an async call
It's seems not perfect, but works, thank you.
Re: How to turn thread spawn call into an async call
I agree that would be fine. The two are very similar. To avoid the polling, threadpool should be able to transfer the result of its work to the async dispatch list of the calling thread when its done. expanding my example you could do: import os, asyncdispatch, threadpool type Noise = distinct bool proc doWork(param: int): Noise = # staff use sql echo "starting with ", param, " ..." sleep(5000) # complete the future var echo "... ok" proc doOtherWork(p1:int, p2: int): Noise = echo "other starting with ", p1, " and ", p2, " ..." sleep(4000) # complete the future var echo "... other ok" proc doRealWork(p1, p2, p3: int): int = echo "real starting with ", p1, " and ", p2, " and ", p3, " ..." sleep(3000) result = p1 + p2 + p3 echo "... done real work" proc asyncWaitFor (work: FlowVar[Noise], sleepTime: int = 500) {.async.} = ## waits asynchron for a FlowVar to finish while not work.isReady : await sleepAsync(sleepTime) proc asyncWaitFor[T: not Noise] (work: FlowVar[T], sleepTime: int = 500):Future[T] {.async.} = ## waits asynchron for a FlowVar to finish while not work.isReady : await sleepAsync(sleepTime) return ^work proc callWorkAsync() {.async.} = let work = spawn doWork(1) let other = spawn doOtherWork(2, 3) let real = spawn doRealWork(4, 5, 6) let res = await asyncWaitFor(real) echo "real work returned: ", res await asyncWaitFor(work) await asyncWaitFor(other) let call = callWorkAsync() echo "do so more" waitFor call echo "done"
Re: How to turn thread spawn call into an async call
I think what I really need is a new spawn which return a Future[T] rather than FlowVar[T].
Re: How to turn thread spawn call into an async call
Now there is another problem. I hope I can write the code like this: proc ff1(p1: int): Result = # my db acess code here .. proc ff2(p1, p2: int): Result = # my db acess code here .. proc main() {.async.} = # async call ff1 with parameter let r1 = await callAsync(ff1(1)) # async call ff2 with parameter let r2 = await callAsync(ff2(1, 2)) .. Because we pass the parameter 'ff1(1)' to callAsync, so callAsync must be a macro like this: macro callAsync*(p: untyped): untyped {.async.} = quote do: proc callme(evt: AsyncEvent): Result = let s = `p` evt.trigger() s let evt = newAsyncEvent() let fut = waitEvent(evt) let val = spawn callme(evt) await fut return ^val But a macro cannot be {.async.}, so I cannot do this. A limited way to resolve this problem is use an procval, here is the code: type Result* = ref object of RootObj body*: string Action = proc(): Result proc waitEvent(evt: AsyncEvent): Future[void] = let fut = newFuture[void]("callAsync") addEvent(evt, (fd: AsyncFD) => (fut.complete(); true)) return fut proc callp(evt: AsyncEvent, p: Action): Result = let v = p() evt.trigger() v proc callAsync*(p: Action): Future[Result] {.async.} = let evt = newAsyncEvent() let fut = waitEvent(evt) let val = spawn callp(evt, p) await fut return ^val proc ff(): Result = echo "work" sleep(1000) Result(body: "hello") block: let val = waitFor callAsync(ff) echo "future return ", val.body The limitation is I can only call Action type proc, and I cannot pass the paramter freely. Any way to solve the problem? Thanks.
Re: How to turn thread spawn call into an async call
@adrianv Thank you
Re: How to turn thread spawn call into an async call
you can also busy poll the result of the spawned proc in an async proc like that: import os, asyncdispatch, threadpool proc doWork(): bool = # staff use sql echo "starting..." sleep(5000) # complete the future var echo "... ok" return true proc asyncWaitFor[T] (work: FlowVar[T], sleepTime: int = 500):Future[T] {.async.} = ## waits asynchron for a FlowVar to finish while not work.isReady : await sleepAsync(sleepTime) return ^work proc callWorkAsync() {.async.} = let work = spawn doWork() discard await asyncWaitFor(work) let call = callWorkAsync() echo "do so more" waitFor call echo "done"
Re: How to turn thread spawn call into an async call
@2vg asyncpg is good, thank you!
Re: How to turn thread spawn call into an async call
Find a way to solve the problem. Here is the code: proc doWork(evt: AsyncEvent) {.gcsafe.} = sleep(3000) evt.trigger() echo "work over" proc waitEvent(ev: AsyncEvent): Future[void] = var fut = newFuture[void]("waitEvent") proc cb(fd: AsyncFD): bool = fut.complete(); return true addEvent(ev, cb) return fut proc callAsync() {.async.} = let evt = newAsyncEvent() let fut = waitEvent(evt) spawn doWork(evt) await fut waitFor callAsync() echo "future return"
Re: How to turn thread spawn call into an async call
Have you tried this? [asyncpg](https://github.com/cheatfate/asyncpg) To wait for some result of Spawn's task, you can confirm by using isReady() function. For example, [ChatApp#L38](https://github.com/dom96/nim-in-action-code/blob/master/Chapter3/ChatApp/src/client.nim#L38)