Removed spawn_link and AsyncJob; added Job class that does the same

This commit is contained in:
Denis Bilenko
2008-12-10 18:00:27 +06:00
parent 59b59acd23
commit bd2444f8bf
4 changed files with 47 additions and 27 deletions

View File

@@ -238,11 +238,23 @@ class event(object):
return self.send(None, args)
class AsyncJob(object):
class Job(object):
"""Spawn a new coroutine to execute a function and collect its result.
def __init__(self, greenlet_ref, event):
self.greenlet_ref = greenlet_ref
self.event = event
use wait() method to collect the result of the function;
use kill() method to kill the greenlet running the function.
"""
def __init__(self, function, *args, **kwargs):
"""Create a new coroutine, or cooperative thread of control, within which
to execute *function*.
``Job()`` returns control to the caller immediately, and *function*
will be called in a future main loop iteration.
"""
self.event = event()
g = api.spawn(wrap_result_in_event, weakref.ref(self.event), function, *args, **kwargs)
self.greenlet_ref = weakref.ref(g)
@property
def greenlet(self):
@@ -263,6 +275,13 @@ class AsyncJob(object):
return '<%s greenlet=%r%s event=%s>' % (klass, self.greenlet, dead, self.event)
def wait(self):
"""Wait for the function to return or raise.
Return the return value of the function if it has returned one,
re-raise the exception that was raised by the function otherwise.
If the greenlet was killed(), e.g. with kill() method, GreenletExit()
object is returned.
"""
return self.event.wait()
def poll(self, notready=None):
@@ -287,9 +306,15 @@ def _kill_by_ref(async_job_ref):
if async_job is not None:
async_job.kill()
def _wrap_result_in_event(event_ref, func, *args, **kwargs):
def wrap_result_in_event(event_ref, function, *args, **kwargs):
"""Execute *function*, send its result to event_ref().
If function raises GreenletExit() it's trapped and sent as a regular value.
If event_ref() is not available (event was GC-ed) the return value
is thrown away and the exception is re-raised (allowing hub to log
the exception)
"""
try:
result = func(*args, **kwargs)
result = function(*args, **kwargs)
except api.GreenletExit, ex:
event = event_ref()
if event is not None:
@@ -305,11 +330,6 @@ def _wrap_result_in_event(event_ref, func, *args, **kwargs):
if event is not None:
event.send(result)
def spawn_link(func, *args, **kwargs):
result = event()
g = api.spawn(_wrap_result_in_event, weakref.ref(result), func, *args, **kwargs)
return AsyncJob(weakref.ref(g), result)
class multievent(object):
"""is an event that can hold more than one value (it cannot be cancelled though)

View File

@@ -1,12 +1,12 @@
"""Spawn multiple greenlet-workers and collect their results.
Demonstrates how to use spawn_link.
Demonstrates how to use coros.Job.
"""
import sys
import string
from eventlet.api import sleep
from eventlet.green import socket
from eventlet.coros import spawn_link
from eventlet.coros import Job
# this example works with both standard eventlet hubs and with twisted-based hub
# comment out the following line to use standard eventlet hub
@@ -24,10 +24,10 @@ def progress_indicator():
sys.stderr.write('.')
sleep(0.5)
spawn_link(progress_indicator)
Job(progress_indicator)
urls = ['www.%s.com' % (x*3) for x in string.letters]
jobs = [spawn_link(geturl, x) for x in urls]
jobs = [Job(geturl, x) for x in urls]
print 'spawned %s jobs' % len(jobs)

View File

@@ -1,6 +1,6 @@
import sys
from twisted.internet import reactor
from eventlet.coros import event, spawn_link
from eventlet.coros import event, Job
from eventlet.twistedutil import join_reactor
from eventlet.twistedutil.protocol import GreenClientCreator, SpawnFactory, UnbufferedTransport
@@ -18,8 +18,8 @@ def forward(from_, to):
def handler(local):
remote = GreenClientCreator(reactor, UnbufferedTransport).connectTCP(remote_host, remote_port)
error = event()
a = spawn_link(forward, remote, local)
b = spawn_link(forward, local, remote)
a = Job(forward, remote, local)
b = Job(forward, local, remote)
a.wait()
b.wait()

View File

@@ -1,6 +1,6 @@
import unittest
import sys
from eventlet.coros import event, spawn_link
from eventlet.coros import event, Job
from eventlet.api import spawn, sleep, GreenletExit, exc_after
class TestEvent(unittest.TestCase):
@@ -22,15 +22,15 @@ class TestEvent(unittest.TestCase):
assert log == [('catched', 'Exception')], log
class TestSpawnLink(unittest.TestCase):
class TestJob(unittest.TestCase):
def test_simple_return(self):
res = spawn_link(lambda: 25).wait()
res = Job(lambda: 25).wait()
assert res==25, res
def test_exception(self):
try:
spawn_link(sys.exit, 'bye').wait()
Job(sys.exit, 'bye').wait()
except SystemExit, ex:
assert ex.args == ('bye', )
else:
@@ -40,7 +40,7 @@ class TestSpawnLink(unittest.TestCase):
def func():
sleep(0.1)
return 101
res = spawn_link(func)
res = Job(func)
assert res
if sync:
res.kill()
@@ -60,14 +60,14 @@ class TestSpawnLink(unittest.TestCase):
def func():
sleep(0.1)
return 25
job = spawn_link(func)
job = Job(func)
self.assertEqual(job.poll(), None)
assert job, repr(job)
self.assertEqual(job.wait(), 25)
self.assertEqual(job.poll(), 25)
assert not job, repr(job)
job = spawn_link(func)
job = Job(func)
self.assertEqual(job.poll(5), 5)
assert job, repr(job)
self.assertEqual(job.wait(), 25)
@@ -78,12 +78,12 @@ class TestSpawnLink(unittest.TestCase):
def func():
sleep(0.1)
return 25
job = spawn_link(func)
job = Job(func)
job.kill_after(0.05)
result = job.wait()
assert isinstance(result, GreenletExit), repr(result)
job = spawn_link(func)
job = Job(func)
job.kill_after(0.2)
self.assertEqual(job.wait(), 25)
sleep(0.2)