Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spawning functions asynchronously using Gevents

I was undergoing Gevents ( python library for asych functionality ) and wrote a very small program to understand how it works , but the results were quite baffling. The below is the code

import gevent 
import time 


def mytime(t):
    time.sleep(t)
    print " i have slept for ",t,"secs"

x = range (0,10)
x.reverse()

for i in x :
    jobs = [ gevent.spawn(mytime , i) ] 
gevent.joinall(jobs)

The output no matter how many times i run , i get

 i have slept for  9 secs
 i have slept for  8 secs
 i have slept for  7 secs
 i have slept for  6 secs
 i have slept for  5 secs
 i have slept for  4 secs
 i have slept for  3 secs
 i have slept for  2 secs
 i have slept for  1 secs
 i have slept for  0 secs

There is a similar example , presented as a part of gevent tutorials.

where the asynch functionality is pretty apparent . All i have done is to add a sleep functionality in the code. shouldnt the output be something like this ??

     i have slept for  6 secs
     i have slept for  8 secs
     i have slept for  5 secs
     i have slept for  9 secs
     i have slept for  7 secs
     i have slept for  0 secs
     i have slept for  3 secs
     i have slept for  2 secs
     i have slept for  1 secs
     i have slept for  4 secs
like image 562
Rahul Avatar asked Feb 07 '12 05:02

Rahul


People also ask

Is gevent asynchronous?

Gevent functions aren't running asynchronously.

What is gevent spawn?

gevent is a coroutine -based Python networking library that uses greenlet to provide a high-level synchronous API on top of the libev or libuv event loop. Features include: Fast event loop based on libev or libuv. Lightweight execution units based on greenlets.

How does gevent work?

Overview. gevent is a coroutine-based cooperative multitasking python framework that relies on monkey patching to make all code cooperative. Gevent actually draws its lineage from Eve Online which was implemented using Stackless Python which eventually evolved into eventlet which inspired gevent.

What is monkey patching gevent?

monkey – Make the standard library cooperative. Make the standard library cooperative. The primary purpose of this module is to carefully patch, in place, portions of the standard library with gevent-friendly functions that behave in the same way as the original (at least as closely as possible).


2 Answers

Your reaction to the tutorial seems to show that you've missed part of what it's trying to show.

In the asynchronous part of the tutorial's code, the main reason that the tasks finish in a random order is because they've slept for a random period of time.

They still sleep for a random period of time in the synchronous portion of the code, but because each task is executed after the previous one has finished, they finish in that sequential order too.

The difference between your's and the async tutorial's code, is that you sleep for a predetermined amount of time, and so your tasks should finish that amount of time later, also in a predetermined fashion.

Lastly, however, if you're observant, you'll notice that they finish in the reverse order you might expect them to.

Why is this?

Because you've inserted blocking code into your example. The blocking code is time.sleep(). When something is blocking, that means it has grabbed all execution for itself, and will not let anything else (for example, your other greenlets) run until it has finished.

Since this is the only 'work' that each function does, it has the effect of making your code synchronous again.

In writing these sorts of programs, you want to make blocking code as non-existent as possible. You must be aware of writing possibly blocking code all the time, and you usually want to find non-blocking alternatives as often as possible.

Gevent provides a non-blocking version of time.sleep() - gevent.sleep(). You'll note that's what the tutorial code uses. Your are also able to monkey patch that function. For the moment, you'd normally prefer to just use gevent's version.

Looking at the list of things that monkey_patch patches, should give you a good, but non-exhaustive overview of the types of normal things that are usually blocking.

edit: You also have incorrect logic in your job creating loop.

better is-

jobs = []
for i in x:
    jobs.append(gevent.spawn(mytime, i))

or more simply, just:

jobs = [gevent.spawn(mytime, i) for i in x]
like image 97
Ivo Avatar answered Oct 02 '22 00:10

Ivo


You should use gevent.sleep() instead of time.sleep() here to get correct output:

import gevent

def mytime(t):
    gevent.sleep(t) #NOTE: not time.sleep()
    print " i have slept for ",t,"secs"

jobs = [gevent.spawn(mytime, i) for i in reversed(range(10))]
gevent.joinall(jobs)

Output

 i have slept for  0 secs
 i have slept for  1 secs
 i have slept for  2 secs
 i have slept for  3 secs
 i have slept for  4 secs
 i have slept for  5 secs
 i have slept for  6 secs
 i have slept for  7 secs
 i have slept for  8 secs
 i have slept for  9 secs

The larger i the later mytime(i) produces the output regardless the order mytime(i) is spawned.

You could use time.sleep() if you monkeypatch it first:

import gevent.monkey
gevent.monkey.patch_time()

import time
like image 22
jfs Avatar answered Oct 01 '22 23:10

jfs