Performance Analysis: Goroutine & Python’s Coroutine

I made 1000 HTTP requests using Goroutines and Python’s Coroutines

  • Used Go 1.6.2 and Python 3.6
  • Implemented in Go using net/http package
  • Implemented in Python using aiohttp, requests and urllib3 libraries
  • Ran it over $10 DigitalOcean droplet

Scroll to bottom of this post to see results.

Go

Go implementation using goroutines:

package main

import (
    "fmt"
    "net/http"
)


func main() {
    url := "http://example.com"
    resc, errc := make(chan bool), make(chan error)

    for i := 0; i < 1000; i++ {
        go func(url string) {
            _, err := http.Head(url)
            if err != nil {
                errc <- err
                return
            }
            resc <- true
        }(url)
    }
    for i := 0; i < 1000; i++ {
        select {
        case <-resc:
        case err := <-errc:
            fmt.Println(err)
        }
    }
}

Python

Python implementation using asyncio with aiohttp, requests and urllib3

1. aiohttp

import asyncio

import aiohttp


async def main():
    async with aiohttp.ClientSession() as session:
        for i in range(1000):
            await session.head('http://example.com')


if __name__ == '__main__':
    loop = asyncio.get_event_loop()
    loop.run_until_complete(main())

2. requests

import asyncio

import requests


async def main():
    futures = [
        loop.run_in_executor(
            None,
            requests.get,
            'http://example.com'
        )
        for i in range(1000)
    ]
    return await asyncio.gather(*futures)


if __name__ == '__main__':
    loop = asyncio.get_event_loop()
    _ = loop.run_until_complete(main())

3. urllib3

import asyncio
import urllib3


async def main(http):
    futures = [
        loop.run_in_executor(
            None,
            http.request,
            'HEAD', 'http://example.com'
        )
        for i in range(1000)
    ]
    return await asyncio.gather(*futures)


if __name__ == '__main__':
    loop = asyncio.get_event_loop()
    http = urllib3.PoolManager()
    _ = loop.run_until_complete(main(http))

Analysis (Time)

1. Sync/Async HEAD requests (time in seconds)

2. Sync/Async GET requests (time in seconds)


Analysis (Memory)

1. Sync/Async HEAD requests (memory in MB)

2. Async/Sync GET requests (memory in MB)

Code for both synchronous and asynchronous implementations are at: https://github.com/vipul-sharma20/async-go-py