Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Concurrency with Gevent

Concurrency with Gevent

Presented last October 2013 meetup of Pizzapy (http://pizzapy.ph/)

Marconi Moreto

October 29, 2013
Tweet

More Decks by Marconi Moreto

Other Decks in Programming

Transcript

  1. Concurrency with Gevent
    Marconi Moreto
    @marconimjr

    View full-size slide

  2. Concurrency
    From Wikipedia:
    “... concurrency is a property of systems in which
    several computations are executing simultaneously,
    and potentially interacting with each other”
    Gevent
    “gevent is a coroutine-based Python networking
    library that uses greenlet to provide a high-level
    synchronous API on top of the libevent event loop”
    From http://www.gevent.org

    View full-size slide

  3. Concurrency is not
    Parallelism
    “Concurrency is not parallelism, although it enables
    parallelism. If you have only one processor, your
    program can still be concurrent but it cannot be
    parallel.”
    - Rob Pike

    View full-size slide

  4. Lets see some code
    Stand back, I know concurrency

    View full-size slide

  5. import time
    import random
    def worker(multiplier):
    time.sleep(random.random())
    print '*' * multiplier
    for i in range(1, 6):
    worker(i)
    Synchronous

    View full-size slide

  6. import time
    import random
    def worker(multiplier):
    time.sleep(random.random())
    print '*' * multiplier
    for i in range(1, 6):
    worker(i)
    Synchronous
    *
    **
    ***
    ****
    *****
    Output:

    View full-size slide

  7. import time
    import random
    def worker(multiplier):
    time.sleep(random.random())
    print '*' * multiplier
    for i in range(1, 6):
    worker(i)
    Synchronous
    *
    **
    ***
    ****
    *****
    Output:
    worker(1)
    worker(2)
    worker(3)
    worker(4)
    worker(5)

    View full-size slide

  8. import time
    import random
    def worker(multiplier):
    time.sleep(random.random())
    print '*' * multiplier
    for i in range(1, 6):
    worker(i)
    Synchronous
    *
    **
    ***
    ****
    *****
    Output:
    worker(1)
    worker(2)
    worker(3)
    worker(4)
    worker(5)
    Start
    Stop

    View full-size slide

  9. import time
    import random
    def worker(multiplier):
    time.sleep(random.random())
    print '*' * multiplier
    for i in range(1, 6):
    worker(i)
    Synchronous
    *
    **
    ***
    ****
    *****
    Output:
    worker(1)
    worker(2)
    worker(3)
    worker(4)
    worker(5)
    Start
    Stop

    View full-size slide

  10. import gevent
    import random
    def worker(multiplier):
    gevent.sleep(random.random())
    print '*' * multiplier
    greenlets = [gevent.spawn(worker, i)
    for i in range(1, 6)]
    gevent.joinall(greenlets)
    Asynchronous printing workers

    View full-size slide

  11. import gevent
    import random
    def worker(multiplier):
    gevent.sleep(random.random())
    print '*' * multiplier
    greenlets = [gevent.spawn(worker, i)
    for i in range(1, 6)]
    gevent.joinall(greenlets)
    Asynchronous printing workers
    *****
    ****
    *
    **
    ***
    Output:

    View full-size slide

  12. import gevent
    import random
    def worker(multiplier):
    gevent.sleep(random.random())
    print '*' * multiplier
    greenlets = [gevent.spawn(worker, i)
    for i in range(1, 6)]
    gevent.joinall(greenlets)
    Asynchronous printing workers
    *****
    ****
    *
    **
    ***
    Output:
    worker(1)
    worker(2)
    worker(3)
    worker(4)
    worker(5)

    View full-size slide

  13. import gevent
    import random
    def worker(multiplier):
    gevent.sleep(random.random())
    print '*' * multiplier
    greenlets = [gevent.spawn(worker, i)
    for i in range(1, 6)]
    gevent.joinall(greenlets)
    Asynchronous printing workers
    *****
    ****
    *
    **
    ***
    Output:
    worker(1)
    worker(2)
    worker(3)
    worker(4)
    worker(5)
    1

    View full-size slide

  14. import gevent
    import random
    def worker(multiplier):
    gevent.sleep(random.random())
    print '*' * multiplier
    greenlets = [gevent.spawn(worker, i)
    for i in range(1, 6)]
    gevent.joinall(greenlets)
    Asynchronous printing workers
    *****
    ****
    *
    **
    ***
    Output:
    worker(1)
    worker(2)
    worker(3)
    worker(4)
    worker(5)
    1
    2

    View full-size slide

  15. import gevent
    import random
    def worker(multiplier):
    gevent.sleep(random.random())
    print '*' * multiplier
    greenlets = [gevent.spawn(worker, i)
    for i in range(1, 6)]
    gevent.joinall(greenlets)
    Asynchronous printing workers
    *****
    ****
    *
    **
    ***
    Output:
    worker(1)
    worker(2)
    worker(3)
    worker(4)
    worker(5)
    3
    1
    2

    View full-size slide

  16. import gevent
    import random
    def worker(multiplier):
    gevent.sleep(random.random())
    print '*' * multiplier
    greenlets = [gevent.spawn(worker, i)
    for i in range(1, 6)]
    gevent.joinall(greenlets)
    Asynchronous printing workers
    *****
    ****
    *
    **
    ***
    Output:
    worker(1)
    worker(2)
    worker(3)
    worker(4)
    worker(5)
    3
    1
    2
    4

    View full-size slide

  17. import gevent
    import random
    def worker(multiplier):
    gevent.sleep(random.random())
    print '*' * multiplier
    greenlets = [gevent.spawn(worker, i)
    for i in range(1, 6)]
    gevent.joinall(greenlets)
    Asynchronous printing workers
    *****
    ****
    *
    **
    ***
    Output:
    worker(1)
    worker(2)
    worker(3)
    worker(4)
    worker(5)
    3
    1
    2
    4
    5

    View full-size slide

  18. import gevent
    import random
    def worker(multiplier):
    gevent.sleep(random.random())
    print '*' * multiplier
    greenlets = [gevent.spawn(worker, i)
    for i in range(1, 6)]
    gevent.joinall(greenlets, timeout=0.5)
    Workers with timeout

    View full-size slide

  19. import gevent
    import random
    def worker(multiplier):
    gevent.sleep(random.random())
    print '*' * multiplier
    greenlets = [gevent.spawn(worker, i)
    for i in range(1, 6)]
    gevent.joinall(greenlets, timeout=0.5)
    Workers with timeout
    ****
    *
    ***
    Output:

    View full-size slide

  20. import gevent
    import random
    def worker(multiplier):
    gevent.sleep(random.random())
    print '*' * multiplier
    greenlets = [gevent.spawn(worker, i)
    for i in range(1, 6)]
    gevent.joinall(greenlets, timeout=0.5)
    Workers with timeout
    ****
    *
    ***
    Output:
    worker(1)
    worker(2)
    worker(3)
    worker(4)
    worker(5)

    View full-size slide

  21. 1
    import gevent
    import random
    def worker(multiplier):
    gevent.sleep(random.random())
    print '*' * multiplier
    greenlets = [gevent.spawn(worker, i)
    for i in range(1, 6)]
    gevent.joinall(greenlets, timeout=0.5)
    Workers with timeout
    ****
    *
    ***
    Output:
    worker(1)
    worker(2)
    worker(3)
    worker(4)
    worker(5)

    View full-size slide

  22. 1
    import gevent
    import random
    def worker(multiplier):
    gevent.sleep(random.random())
    print '*' * multiplier
    greenlets = [gevent.spawn(worker, i)
    for i in range(1, 6)]
    gevent.joinall(greenlets, timeout=0.5)
    Workers with timeout
    ****
    *
    ***
    Output:
    worker(1)
    worker(2)
    worker(3)
    worker(4)
    worker(5)
    2

    View full-size slide

  23. 1
    import gevent
    import random
    def worker(multiplier):
    gevent.sleep(random.random())
    print '*' * multiplier
    greenlets = [gevent.spawn(worker, i)
    for i in range(1, 6)]
    gevent.joinall(greenlets, timeout=0.5)
    Workers with timeout
    ****
    *
    ***
    Output:
    worker(1)
    worker(2)
    worker(3)
    worker(4)
    worker(5)
    2
    3

    View full-size slide

  24. 1
    Timeout
    import gevent
    import random
    def worker(multiplier):
    gevent.sleep(random.random())
    print '*' * multiplier
    greenlets = [gevent.spawn(worker, i)
    for i in range(1, 6)]
    gevent.joinall(greenlets, timeout=0.5)
    Workers with timeout
    ****
    *
    ***
    Output:
    worker(1)
    worker(2)
    worker(3)
    worker(4)
    worker(5)
    2
    3

    View full-size slide

  25. import random
    import gevent
    def worker(multiplier):
    gevent.sleep(random.random())
    return '*' * multiplier
    def producers():
    greenlets = [gevent.spawn(worker, i)
    for i in range(1, 6)]
    gevent.joinall(greenlets)
    return [g.value for g in greenlets]
    print '\n'.join(producers())
    Collecting workers result

    View full-size slide

  26. import random
    import gevent
    def worker(multiplier):
    gevent.sleep(random.random())
    return '*' * multiplier
    def producers():
    greenlets = [gevent.spawn(worker, i)
    for i in range(1, 6)]
    gevent.joinall(greenlets)
    return [g.value for g in greenlets]
    print '\n'.join(producers())
    Collecting workers result
    *
    **
    ***
    ****
    *****
    Output:

    View full-size slide

  27. import random
    import gevent
    def worker(multiplier):
    gevent.sleep(random.random())
    return '*' * multiplier
    def producers():
    greenlets = [gevent.spawn(worker, i)
    for i in range(1, 6)]
    gevent.joinall(greenlets)
    return [g.value for g in greenlets]
    print '\n'.join(producers())
    Collecting workers result
    *
    **
    ***
    ****
    *****
    Output:
    worker(1)
    worker(2)
    worker(3)
    worker(4)
    worker(5)

    View full-size slide

  28. import random
    import gevent
    def worker(multiplier):
    gevent.sleep(random.random())
    return '*' * multiplier
    def producers():
    greenlets = [gevent.spawn(worker, i)
    for i in range(1, 6)]
    gevent.joinall(greenlets)
    return [g.value for g in greenlets]
    print '\n'.join(producers())
    Collecting workers result
    *
    **
    ***
    ****
    *****
    Output:
    worker(1)
    worker(2)
    worker(3)
    worker(4)
    worker(5)
    1

    View full-size slide

  29. import random
    import gevent
    def worker(multiplier):
    gevent.sleep(random.random())
    return '*' * multiplier
    def producers():
    greenlets = [gevent.spawn(worker, i)
    for i in range(1, 6)]
    gevent.joinall(greenlets)
    return [g.value for g in greenlets]
    print '\n'.join(producers())
    Collecting workers result
    *
    **
    ***
    ****
    *****
    Output:
    worker(1)
    worker(2)
    worker(3)
    worker(4)
    worker(5)
    1
    2

    View full-size slide

  30. import random
    import gevent
    def worker(multiplier):
    gevent.sleep(random.random())
    return '*' * multiplier
    def producers():
    greenlets = [gevent.spawn(worker, i)
    for i in range(1, 6)]
    gevent.joinall(greenlets)
    return [g.value for g in greenlets]
    print '\n'.join(producers())
    Collecting workers result
    *
    **
    ***
    ****
    *****
    Output:
    worker(1)
    worker(2)
    worker(3)
    worker(4)
    worker(5)
    3
    1
    2

    View full-size slide

  31. import random
    import gevent
    def worker(multiplier):
    gevent.sleep(random.random())
    return '*' * multiplier
    def producers():
    greenlets = [gevent.spawn(worker, i)
    for i in range(1, 6)]
    gevent.joinall(greenlets)
    return [g.value for g in greenlets]
    print '\n'.join(producers())
    Collecting workers result
    *
    **
    ***
    ****
    *****
    Output:
    worker(1)
    worker(2)
    worker(3)
    worker(4)
    worker(5)
    3
    1
    2
    4

    View full-size slide

  32. import random
    import gevent
    def worker(multiplier):
    gevent.sleep(random.random())
    return '*' * multiplier
    def producers():
    greenlets = [gevent.spawn(worker, i)
    for i in range(1, 6)]
    gevent.joinall(greenlets)
    return [g.value for g in greenlets]
    print '\n'.join(producers())
    Collecting workers result
    *
    **
    ***
    ****
    *****
    Output:
    worker(1)
    worker(2)
    worker(3)
    worker(4)
    worker(5)
    3
    1
    2
    4
    5

    View full-size slide

  33. import random
    import gevent
    from gevent.queue import Queue
    tasks = Queue()
    def worker(multiplier):
    gevent.sleep(random.random())
    tasks.put('*' * multiplier)
    def producers():
    greenlets = [gevent.spawn(worker, i)
    for i in range(1, 6)]
    gevent.joinall(greenlets)
    def consumer():
    while True:
    print tasks.get()
    gevent.spawn(consumer)
    producers()
    Producers and consumer (1/2)

    View full-size slide

  34. import random
    import gevent
    from gevent.queue import Queue
    tasks = Queue()
    def worker(multiplier):
    gevent.sleep(random.random())
    tasks.put('*' * multiplier)
    def producers():
    greenlets = [gevent.spawn(worker, i)
    for i in range(1, 6)]
    gevent.joinall(greenlets)
    def consumer():
    while True:
    print tasks.get()
    gevent.spawn(consumer)
    producers()
    Producers and consumer (1/2)
    ***
    *
    **
    ****
    *****
    Output:

    View full-size slide

  35. worker(1)
    worker(2)
    worker(3)
    worker(4)
    worker(5)
    Producers and consumer (2/2)
    Queue
    Head

    View full-size slide

  36. worker(1)
    worker(2)
    worker(3)
    worker(4)
    worker(5)
    1
    Producers and consumer (2/2)
    Queue
    Head

    View full-size slide

  37. worker(1)
    worker(2)
    worker(3)
    worker(4)
    worker(5)
    1
    Producers and consumer (2/2)
    Queue
    Head

    View full-size slide

  38. worker(1)
    worker(2)
    worker(3)
    worker(4)
    worker(5)
    1
    Producers and consumer (2/2)
    Queue
    Head
    ***

    View full-size slide

  39. worker(1)
    worker(2)
    worker(3)
    worker(4)
    worker(5)
    1
    Producers and consumer (2/2)
    Queue
    Head
    ***

    View full-size slide

  40. worker(1)
    worker(2)
    worker(3)
    worker(4)
    worker(5)
    1
    Producers and consumer (2/2)
    Queue
    Head Consumer
    ***

    View full-size slide

  41. worker(1)
    worker(2)
    worker(3)
    worker(4)
    worker(5)
    1
    Producers and consumer (2/2)
    Queue
    Head Consumer
    ***

    View full-size slide

  42. worker(1)
    worker(2)
    worker(3)
    worker(4)
    worker(5)
    2
    1
    Producers and consumer (2/2)
    Queue
    Head Consumer
    ***

    View full-size slide

  43. worker(1)
    worker(2)
    worker(3)
    worker(4)
    worker(5)
    2
    1
    Producers and consumer (2/2)
    Queue
    Head Consumer
    ***

    View full-size slide

  44. worker(1)
    worker(2)
    worker(3)
    worker(4)
    worker(5)
    2
    1
    Producers and consumer (2/2)
    Queue
    Head Consumer
    ***
    *

    View full-size slide

  45. worker(1)
    worker(2)
    worker(3)
    worker(4)
    worker(5)
    2
    3
    1
    Producers and consumer (2/2)
    Queue
    Head Consumer
    ***
    *

    View full-size slide

  46. worker(1)
    worker(2)
    worker(3)
    worker(4)
    worker(5)
    2
    3
    1
    Producers and consumer (2/2)
    Queue
    Head Consumer
    ***
    *

    View full-size slide

  47. worker(1)
    worker(2)
    worker(3)
    worker(4)
    worker(5)
    2
    3
    1
    Producers and consumer (2/2)
    Queue
    Head Consumer
    ***
    *
    **

    View full-size slide

  48. worker(1)
    worker(2)
    worker(3)
    worker(4)
    worker(5)
    2
    4
    3
    1
    Producers and consumer (2/2)
    Queue
    Head Consumer
    ***
    *
    **

    View full-size slide

  49. worker(1)
    worker(2)
    worker(3)
    worker(4)
    worker(5)
    2
    4
    3
    1
    Producers and consumer (2/2)
    Queue
    Head Consumer
    ***
    *
    **

    View full-size slide

  50. worker(1)
    worker(2)
    worker(3)
    worker(4)
    worker(5)
    2
    4
    3
    1
    Producers and consumer (2/2)
    Queue
    Head Consumer
    ***
    *
    **
    ****

    View full-size slide

  51. worker(1)
    worker(2)
    worker(3)
    worker(4)
    worker(5)
    2
    5
    4
    3
    1
    Producers and consumer (2/2)
    Queue
    Head Consumer
    ***
    *
    **
    ****

    View full-size slide

  52. worker(1)
    worker(2)
    worker(3)
    worker(4)
    worker(5)
    2
    5
    4
    3
    1
    Producers and consumer (2/2)
    Queue
    Head Consumer
    ***
    *
    **
    ****

    View full-size slide

  53. worker(1)
    worker(2)
    worker(3)
    worker(4)
    worker(5)
    2
    5
    4
    3
    1
    Producers and consumer (2/2)
    Queue
    Head Consumer
    ***
    *
    **
    ****
    *****

    View full-size slide

  54. worker(1)
    worker(2)
    worker(3)
    worker(4)
    worker(5)
    2
    5
    4
    3
    1
    Producers and consumer (2/2)
    Queue
    Head Consumer

    View full-size slide

  55. import random
    import gevent
    from gevent.queue import Queue
    from gevent.pool import Pool
    pool = Pool(2)
    tasks = Queue()
    def worker(multiplier):
    gevent.sleep(random.random())
    tasks.put('*' * multiplier)
    def producers():
    pool.map(worker, range(1, 6))
    def consumer():
    while True:
    print tasks.get()
    gevent.spawn(consumer)
    producers()
    Worker pool (1/2)

    View full-size slide

  56. import random
    import gevent
    from gevent.queue import Queue
    from gevent.pool import Pool
    pool = Pool(2)
    tasks = Queue()
    def worker(multiplier):
    gevent.sleep(random.random())
    tasks.put('*' * multiplier)
    def producers():
    pool.map(worker, range(1, 6))
    def consumer():
    while True:
    print tasks.get()
    gevent.spawn(consumer)
    producers()
    Worker pool (1/2)
    **
    *
    ****
    *****
    ***
    Output:

    View full-size slide

  57. Worker pool (2/2)
    Queue
    Head

    View full-size slide

  58. worker(1)
    worker(2)
    Worker pool (2/2)
    Queue
    Head

    View full-size slide

  59. worker(1)
    worker(2)
    1
    Worker pool (2/2)
    Queue
    Head

    View full-size slide

  60. worker(1)
    worker(2)
    1
    Worker pool (2/2)
    Queue
    Head

    View full-size slide

  61. worker(1)
    worker(2)
    1
    Worker pool (2/2)
    **
    Queue
    Head

    View full-size slide

  62. worker(1)
    worker(2)
    1
    Worker pool (2/2)
    **
    Queue
    Head

    View full-size slide

  63. worker(1)
    worker(2)
    1
    Worker pool (2/2)
    **
    Queue
    Head Consumer

    View full-size slide

  64. worker(1)
    worker(2)
    1
    Worker pool (2/2)
    **
    Queue
    Head Consumer

    View full-size slide

  65. worker(1)
    worker(2)
    2
    1
    Worker pool (2/2)
    **
    Queue
    Head Consumer

    View full-size slide

  66. worker(1)
    worker(2)
    2
    1
    Worker pool (2/2)
    **
    Queue
    Head Consumer

    View full-size slide

  67. worker(1)
    worker(2)
    2
    1
    Worker pool (2/2)
    **
    *
    Queue
    Head Consumer

    View full-size slide

  68. worker(1)
    worker(2)
    worker(4)
    worker(5)
    2
    1
    Worker pool (2/2)
    **
    *
    Queue
    Head Consumer

    View full-size slide

  69. worker(1)
    worker(2)
    worker(4)
    worker(5)
    2
    3
    1
    Worker pool (2/2)
    **
    *
    Queue
    Head Consumer

    View full-size slide

  70. worker(1)
    worker(2)
    worker(4)
    worker(5)
    2
    3
    1
    Worker pool (2/2)
    **
    *
    Queue
    Head Consumer

    View full-size slide

  71. worker(1)
    worker(2)
    worker(4)
    worker(5)
    2
    3
    1
    Worker pool (2/2)
    **
    *
    ****
    Queue
    Head Consumer

    View full-size slide

  72. worker(1)
    worker(2)
    worker(4)
    worker(5)
    2
    4
    3
    1
    Worker pool (2/2)
    **
    *
    ****
    Queue
    Head Consumer

    View full-size slide

  73. worker(1)
    worker(2)
    worker(4)
    worker(5)
    2
    4
    3
    1
    Worker pool (2/2)
    **
    *
    ****
    Queue
    Head Consumer

    View full-size slide

  74. worker(1)
    worker(2)
    worker(4)
    worker(5)
    2
    4
    3
    1
    Worker pool (2/2)
    **
    *
    ****
    *****
    Queue
    Head Consumer

    View full-size slide

  75. worker(1)
    worker(2)
    worker(3)
    worker(4)
    worker(5)
    2
    4
    3
    1
    Worker pool (2/2)
    **
    *
    ****
    *****
    Queue
    Head Consumer

    View full-size slide

  76. worker(1)
    worker(2)
    worker(3)
    worker(4)
    worker(5)
    2
    4
    3
    1
    5
    Worker pool (2/2)
    **
    *
    ****
    *****
    Queue
    Head Consumer

    View full-size slide

  77. worker(1)
    worker(2)
    worker(3)
    worker(4)
    worker(5)
    2
    4
    3
    1
    5
    Worker pool (2/2)
    **
    *
    ****
    *****
    Queue
    Head Consumer

    View full-size slide

  78. worker(1)
    worker(2)
    worker(3)
    worker(4)
    worker(5)
    2
    4
    3
    1
    5
    Worker pool (2/2)
    **
    *
    ****
    *****
    ***
    Queue
    Head Consumer

    View full-size slide

  79. But, but, what about real
    examples?

    View full-size slide

  80. Shorty: URL shortener
    - TCP
    - Message framing

    View full-size slide

  81. Shorty: URL shortener
    Client
    - TCP
    - Message framing

    View full-size slide

  82. Shorty: URL shortener
    Client Server
    - TCP
    - Message framing

    View full-size slide

  83. Shorty: URL shortener
    Client Server
    Long URL:
    Length + Payload
    - TCP
    - Message framing

    View full-size slide

  84. Shorty: URL shortener
    Client Server
    Long URL:
    Length + Payload
    - TCP
    - Message framing

    View full-size slide

  85. Shorty: URL shortener
    Client Server
    Long URL:
    Length + Payload
    Shortened URL:
    Length + Payload
    - TCP
    - Message framing

    View full-size slide

  86. Shorty: URL shortener
    Client Server
    Long URL:
    Length + Payload
    Shortened URL:
    Length + Payload
    - TCP
    - Message framing

    View full-size slide

  87. Shorty: URL shortener
    Client Server
    Long URL:
    Length + Payload
    Shortened URL:
    Length + Payload
    - TCP
    - Message framing
    Print short URL

    View full-size slide

  88. Shorty: URL shortener
    Client Server
    Long URL:
    Length + Payload
    Shortened URL:
    Length + Payload
    Close enough :P
    - TCP
    - Message framing
    Print short URL

    View full-size slide

  89. ...
    server = socket(AF_INET, SOCK_STREAM)
    server.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
    server.bind(('', 9000))
    server.listen(500)
    def handle(conn, addr):
    logger.info('connected to {0}'.format(addr))
    time.sleep(1) # delay
    # read payload
    payload_len_buf = read_bytes(conn, PLEN_BUF_SIZE)
    payload_len = struct.unpack('payload_buf = read_bytes(conn, payload_len)
    # shorten url and send it back
    short_url = shorten(payload_buf)
    payload_len = struct.pack('conn.sendall(payload_len + short_url)
    conn.close()
    # accept and handle incoming client connections
    while True:
    conn, addr = server.accept()
    handle(conn, addr)
    Blocking server

    View full-size slide

  90. Client
    ...
    def run():
    # connect to server
    client = socket()
    client.connect(('', 9000))
    # send payload
    payload = 'http://127.0.0.1:5000/{0}'.format(uuid.uuid4())
    payload_len = struct.pack('client.sendall(payload_len + payload)
    # read payload
    payload_len_buf = read_bytes(client, PLEN_BUF_SIZE)
    payload_len = struct.unpack('payload_buf = read_bytes(client, payload_len)
    client.close()
    return payload_buf
    if __name__ == '__main__':
    print run()

    View full-size slide

  91. Client
    ...
    def run():
    # connect to server
    client = socket()
    client.connect(('', 9000))
    # send payload
    payload = 'http://127.0.0.1:5000/{0}'.format(uuid.uuid4())
    payload_len = struct.pack('client.sendall(payload_len + payload)
    # read payload
    payload_len_buf = read_bytes(client, PLEN_BUF_SIZE)
    payload_len = struct.unpack('payload_buf = read_bytes(client, payload_len)
    client.close()
    return payload_buf
    if __name__ == '__main__':
    print run()
    http://127.0.0.1:5000/867nv
    Output:

    View full-size slide

  92. So how does it perform?

    View full-size slide

  93. ...
    CONCURRENCY = 10
    ...
    class Agent(Thread):
    ...
    if __name__ == '__main__':
    runner = Runner()
    start = time.time()
    for _ in range(CONCURRENCY):
    agent = Agent(runner)
    agent.setDaemon(True)
    agent.start()
    print 'spawned {0} agents'.format(runner.spawned_agents)
    while runner.running_agents > 0:
    time.sleep(1)
    print 'connections/second: {0}'.format(runner.conn_per_sec)
    runner.reset_conn_per_sec()
    end = time.time()
    elapsed = end - start
    print 'took: {0}'.format(elapsed)
    Benchmark against
    blocking server

    View full-size slide

  94. ...
    CONCURRENCY = 10
    ...
    class Agent(Thread):
    ...
    if __name__ == '__main__':
    runner = Runner()
    start = time.time()
    for _ in range(CONCURRENCY):
    agent = Agent(runner)
    agent.setDaemon(True)
    agent.start()
    print 'spawned {0} agents'.format(runner.spawned_agents)
    while runner.running_agents > 0:
    time.sleep(1)
    print 'connections/second: {0}'.format(runner.conn_per_sec)
    runner.reset_conn_per_sec()
    end = time.time()
    elapsed = end - start
    print 'took: {0}'.format(elapsed)
    Benchmark against
    blocking server
    Output:
    ...
    took: 11.0153269768

    View full-size slide

  95. What did we discover?
    - Blocks on each request
    - Very slow
    - Poor performance
    - Isn’t web scale

    View full-size slide

  96. import gevent
    from gevent import monkey; monkey.patch_socket()
    from gevent.pool import Pool
    from gevent.socket import socket
    ...
    ...
    pool = Pool(100)
    server = socket(AF_INET, SOCK_STREAM)
    server.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
    server.bind(('', 9000))
    server.listen(50)
    def handle(conn, addr):
    logger.info('connected to {0}'.format(addr))
    gevent.sleep(1) # delay
    ...
    # accept and handle incoming client connections
    while True:
    conn, addr = server.accept()
    pool.spawn(handle, conn, addr)
    Non-blocking server

    View full-size slide

  97. import gevent
    from gevent import monkey; monkey.patch_socket()
    from gevent.pool import Pool
    from gevent.socket import socket
    ...
    ...
    pool = Pool(100)
    server = socket(AF_INET, SOCK_STREAM)
    server.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
    server.bind(('', 9000))
    server.listen(50)
    def handle(conn, addr):
    logger.info('connected to {0}'.format(addr))
    gevent.sleep(1) # delay
    ...
    # accept and handle incoming client connections
    while True:
    conn, addr = server.accept()
    pool.spawn(handle, conn, addr)
    Non-blocking server
    ...
    took: 2.00628781319
    Output:

    View full-size slide

  98. How about now?
    - Doesn’t block on each request
    - Signi!cantly faster
    - Better performance

    View full-size slide

  99. Links
    Gevent home page:
    http://www.gevent.org/
    Gevent for working python developer:
    http://sdiehl.github.io/gevent-tutorial/
    Multi-part !le downloader using gevent:
    https://github.com/marconi/pullite/tree/experiment
    Slides and source !les:
    https://github.com/pizzapy/oct2013-meetup

    View full-size slide

  100. Thank you
    Marconi Moreto
    @marconimjr
    http://marconijr.com
    https://github.com/marconi

    View full-size slide