From: homm Date: Sun, 28 Apr 2013 17:35:48 +0000 (+0400) Subject: Remove reference to last task and his arguments in engine to free memory. X-Git-Tag: v3.1.0~95^2~3 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b4f36e70893ccc4f7ab4c6ec63354dce70c00b2f;p=thirdparty%2Ftornado.git Remove reference to last task and his arguments in engine to free memory. --- diff --git a/tornado/gen.py b/tornado/gen.py index 938fef61b..7f8de1284 100644 --- a/tornado/gen.py +++ b/tornado/gen.py @@ -439,6 +439,9 @@ class _NullYieldPoint(YieldPoint): return None +_null_yield_point = _NullYieldPoint() + + class Runner(object): """Internal implementation of `tornado.gen.engine`. @@ -449,7 +452,7 @@ class Runner(object): def __init__(self, gen, final_callback): self.gen = gen self.final_callback = final_callback - self.yield_point = _NullYieldPoint() + self.yield_point = _null_yield_point self.pending_callbacks = set() self.results = {} self.running = False @@ -505,6 +508,7 @@ class Runner(object): yielded = self.gen.send(next) except (StopIteration, Return) as e: self.finished = True + self.yield_point = _null_yield_point if self.pending_callbacks and not self.had_exception: # If we ran cleanly without waiting on all callbacks # raise an error (really more of a warning). If we @@ -518,6 +522,7 @@ class Runner(object): return except Exception: self.finished = True + self.yield_point = _null_yield_point raise if isinstance(yielded, list): yielded = Multi(yielded) diff --git a/tornado/test/gen_test.py b/tornado/test/gen_test.py index d77297dbf..ae2461e57 100644 --- a/tornado/test/gen_test.py +++ b/tornado/test/gen_test.py @@ -5,6 +5,7 @@ import functools import sys import textwrap import time +import platform from tornado.concurrent import return_future from tornado.escape import url_escape @@ -19,6 +20,8 @@ from tornado import gen skipBefore33 = unittest.skipIf(sys.version_info < (3, 3), 'PEP 380 not available') +skipNotCPython = unittest.skipIf(platform.python_implementation() != 'CPython', + 'Not CPython implementation') class GenEngineTest(AsyncTestCase): @@ -488,6 +491,24 @@ class GenEngineTest(AsyncTestCase): with self.assertRaises(gen.ReturnValueIgnoredError): self.run_gen(f) + @skipNotCPython + def test_task_refcounting(self): + # Task with arguments on CPython should be relased immediately after + # engine stop. And should not be delayed to garbage collection. + class Task(gen.Task): + "Task class which count self instances release." + relased = 0 + def __del__(self): + type(self).relased += 1 + + @gen.engine + def f(): + yield Task(lambda _arg, callback: callback(), Task(None)) + self.stop() + + self.run_gen(f) + self.assertEqual(Task.relased, 2) + class GenCoroutineTest(AsyncTestCase): def setUp(self):