Hello everyone,
I'm not sure if this is right place to ask, basically I'm pretty new to this language, I just switched from Python to Nim.
I'm trying to make some HTTP requests with asyncHttpClient, but they seem extremely slow. There's literally no difference between async and non async. I'm pretty sure I'm making some rookie mistake, and I would be grateful if someone would explain what's the problem with my code.
import asyncdispatch, httpclient
proc nonAsyncHttp() =
var client = newHttpClient()
echo "Non async started"
for i in 0 .. 30:
let resp = client.get("http://example.com")
echo resp.status
echo "Non async finished"
proc asyncHttp() {.async.} =
var client = newAsyncHttpClient()
echo "Async started"
for i in 0 .. 30:
let resp = await client.get("http://example.com")
echo resp.status
echo "Async finished"
waitFor asyncHttp()
nonAsyncHttp()
I tried with other APIs as well. Every time result is the same.As @GengisKaizer pointed out, putting your async calls in a loop like that doesn't really work. When await is called the thread will be paused waiting for that call to complete, and since that is within the loop it will pause the loop and not schedule the next call until the previous one is done. By modifying your code slightly to first queue up all your async calls, and then awaiting all their results shows the benefit of async:
import asyncdispatch, httpclient, times
proc nonAsyncHttp() =
let start = epochTime()
var client = newHttpClient()
echo "Non async started"
for i in 0 .. 30:
let resp = client.get("http://example.com")
echo resp.status
echo "Non async finished in ", epochTime() - start
proc asyncHttp() {.async.} =
let start = epochTime()
echo "Async started"
var futures: seq[Future[AsyncResponse]]
for i in 0 .. 30:
var client = newAsyncHttpClient()
futures.add client.get("http://example.com")
for i in 0 .. 30:
let resp = await futures[i]
echo resp.status
echo "Async finished in ", epochTime() - start
waitFor asyncHttp()
nonAsyncHttp()
On my machine/connection the non-async version takes about 3.8s while the async one takes 0.3s.
That works well. But how can I print status code when response is received? This doesn't seem to work:
import asyncdispatch, httpclient, times
proc httpInfo(client: AsyncHttpClient, url: string): Future[AsyncResponse] {.async.} =
result = await client.get(url)
let statuscode = await result.status
echo "DONE: ", url, " STATUS: ",statuscode
proc asyncHttp() {.async.} =
let start = epochTime()
echo "Async started"
var futures: seq[Future[AsyncResponse]]
for i in 0 .. 30:
var client = newAsyncHttpClient()
futures.add client.httpInfo("http://example.com")
for i in 0 .. 30:
let resp = await futures[i]
echo "Async finished in ", epochTime() - start
waitFor asyncHttp()
I think you need to remove the await in
let statuscode = await result.status
Async calls aren't related to cpu speed (like for loops are), instead they're related to network connection and response time within a timeout (sync calls usually will wait forever if there is no response) Doing for loops like those in the example above are unconsistent, because suppose the server won't respond during some of the async requests, but responds immediately after every sync request, you may even get better performance with sync than async.
This is wrong.
Async calls aren't related to cpu speed
Yes.
instead they're related to network
Yes.
instead they're related to network connection and response time within a timeout
No, they don't related to timeout at all.
sync calls usually will wait forever if there is no response
No, sync calls can have timeouts.
because suppose the server won't respond during some of the async requests, but responds immediately after every sync request
Server don't know if client issued sync or async request.
you may even get better performance with sync than async
No, you won't.