Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save UNIcodeX/f373401b78b037cb77fa515693f1edbb to your computer and use it in GitHub Desktop.

Select an option

Save UNIcodeX/f373401b78b037cb77fa515693f1edbb to your computer and use it in GitHub Desktop.

Revisions

  1. UNIcodeX created this gist Apr 17, 2020.
    93 changes: 93 additions & 0 deletions xmonader-sequential_vs_async_vs_parallel-example.nim
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,93 @@
    # This came from https://github.com/xmonader/nim-linkcheck
    # I just added the parallel example to the code and slightly modified the output formatting.
    # My tests yielded the following numbers
    # Sequential : 6.77 seconds
    # Async : 0.27 seconds (25.07x faster | 3.988% time of sequential | 96.01 % faster)
    # Parallel : 0.34 seconds (19.91x faster | 5.022% time of sequential | 94.98 % faster)

    import os, httpclient
    import strutils
    import times
    import asyncdispatch
    import threadpool

    type
    LinkCheckResult = ref object
    link: string
    state: bool

    proc checkLink(link: string) : LinkCheckResult =
    var client = newHttpClient()
    try:
    return LinkCheckResult(link:link, state:client.get(link).code == Http200)
    except:
    return LinkCheckResult(link:link, state:false)

    proc sequentialLinksChecker(links: seq[string]): void =
    for index, link in links:
    if link.strip() != "":
    let result = checkLink(link)
    echo result.link, " is ", result.state

    proc checkLinkAsync(link: string): Future[LinkCheckResult] {.async.} =
    var client = newAsyncHttpClient()

    let future = client.get(link)
    yield future
    if future.failed:
    return LinkCheckResult(link:link, state:false)
    else:
    let resp = future.read()
    return LinkCheckResult(link:link, state: resp.code == Http200)

    proc asyncLinksChecker(links: seq[string]) {.async.} =
    # client.maxRedirects = 0
    var futures = newSeq[Future[LinkCheckResult]]()
    for index, link in links:
    if link.strip() != "":
    futures.add(checkLinkAsync(link))

    # waitFor -> call async proc from sync proc, await -> call async proc from async proc
    let done = await all(futures)
    for x in done:
    echo x.link, " is ", x.state

    proc checkLinkParallel(link: string) : LinkCheckResult {.thread.} =
    var client = newHttpClient()
    try:
    return LinkCheckResult(link:link, state:client.get(link).code == Http200)
    except:
    return LinkCheckResult(link:link, state:false)

    proc threadsLinksChecker(links: seq[string]): void =
    var LinkCheckResults = newSeq[FlowVar[LinkCheckResult]]()
    for index, link in links:
    LinkCheckResults.add(spawn checkLinkParallel(link))

    for x in LinkCheckResults:
    let res = ^x
    echo res.link, " is ", res.state

    proc main()=
    # echo "Param count: ", paramCount()
    if paramCount() == 1:
    let linksfile = paramStr(1)
    var f = open(linksfile, fmRead)
    let links = readAll(f).splitLines()
    echo "\nSEQUENTIAL:: "
    var t = epochTime()
    sequentialLinksChecker(links)
    echo epochTime()-t
    echo "\nASYNC:: "
    t = epochTime()
    waitFor asyncLinksChecker(links)
    echo epochTime()-t
    echo "\nPARALLEL:: "
    t = epochTime()
    threadsLinksChecker(links)
    echo epochTime()-t

    else:
    echo "Please provide linksfile"

    main()