Re: How to turn thread spawn call into an async call [redux; Nim 1.0.0]

2019-10-12 Thread dom96
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]

2019-10-12 Thread boia01
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

2018-03-19 Thread slangmgh
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

2018-03-18 Thread slangmgh
It's seems not perfect, but works, thank you.


Re: How to turn thread spawn call into an async call

2018-03-17 Thread adrianv
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

2018-03-17 Thread slangmgh
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

2018-03-17 Thread slangmgh
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

2018-03-17 Thread slangmgh
@adrianv Thank you 


Re: How to turn thread spawn call into an async call

2018-03-15 Thread adrianv
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

2018-03-15 Thread slangmgh
@2vg asyncpg is good, thank you! 


Re: How to turn thread spawn call into an async call

2018-03-15 Thread slangmgh
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

2018-03-15 Thread 2vg
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)