Commit 143137a7 authored by Jason Madden's avatar Jason Madden

Inline _get_dict function for more speed.

Final numbers are as follows:

| Operation            	| PyPy 2 	| Python 2.7 	| Python 3.6 	|
|----------------------	|-------:	|-----------:	|-----------:	|
| getattr local        	|   79ns 	|     1580ns 	|     1120ns 	|
| setattr local        	|   86ns 	|     1600ns 	|     1090ns 	|
| getattr subclass     	|   81ns 	|     1640ns 	|     1090ns 	|
| setattr subclass     	|   84ns 	|     1560ns 	|     1090ns 	|
| getattr native local 	|    2ns 	|      139ns 	|       73ns 	|
| setattr native local 	|    2ns 	|      168ns 	|       98ns 	|
parent efe16a2c
......@@ -233,25 +233,14 @@ class _localimpl(object):
return localdict
def _get_dict(self):
impl = _oga(self, '_local__impl')
try:
dct = impl.get_dict()
except KeyError:
dct = impl.create_dict()
args, kw = impl.localargs
self.__init__(*args, **kw)
return dct
_impl_getter = None
_marker = object()
class local(object):
"""
An object whose attributes are greenlet-local.
"""
__slots__ = '_local__impl', '__dict__'
__slots__ = ('_local__impl',)
def __new__(cls, *args, **kw):
if args or kw:
......@@ -270,7 +259,17 @@ class local(object):
def __getattribute__(self, name): # pylint:disable=too-many-return-statements
if name == '__class__':
return _oga(self, name)
dct = _get_dict(self)
# Begin inlined function _get_dict()
impl = _impl_getter(self, local)
try:
dct = impl.get_dict()
except KeyError:
dct = impl.create_dict()
args, kw = impl.localargs
self.__init__(*args, **kw)
# End inlined function _get_dict
if name == '__dict__':
return dct
# If there's no possible way we can switch, because this
......@@ -343,7 +342,17 @@ class local(object):
raise AttributeError(
"%r object attribute '__dict__' is read-only"
% self.__class__.__name__)
dct = _get_dict(self)
# Begin inlined function _get_dict()
impl = _impl_getter(self, local)
try:
dct = impl.get_dict()
except KeyError:
dct = impl.create_dict()
args, kw = impl.localargs
self.__init__(*args, **kw)
# End inlined function _get_dict
type_self = type(self)
if type_self is local:
......@@ -368,7 +377,6 @@ class local(object):
"%r object attribute '__dict__' is read-only"
% self.__class__.__name__)
dct = _get_dict(self)
type_self = type(self)
type_attr = getattr(type_self, name, _marker)
if type_attr is not _marker:
......@@ -378,13 +386,24 @@ class local(object):
type_type_attr.__delete__(type_attr, self)
return
# Otherwise it goes directly in the dict
# Begin inlined function _get_dict()
impl = _impl_getter(self, local)
try:
dct = impl.get_dict()
except KeyError:
dct = impl.create_dict()
args, kw = impl.localargs
self.__init__(*args, **kw)
# End inlined function _get_dict
try:
del dct[name]
except KeyError:
raise AttributeError(name)
def __copy__(self):
impl = object.__getattribute__(self, '_local__impl')
impl = _oga(self, '_local__impl')
current = getcurrent()
currentId = id(current)
d = impl.get_dict()
......@@ -402,3 +421,5 @@ class local(object):
new_impl.dicts[currentId] = (tpl[0], duplicate)
return instance
_impl_getter = local._local__impl.__get__
......@@ -67,7 +67,7 @@ class GeventLocalTestCase(greentest.TestCase):
tearDown = setUp
def test_create_localot_subclass_init_args(self):
def test_create_local_subclass_init_args(self):
with self.assertRaisesRegex(TypeError,
"Initialization arguments are not supported"):
local("foo")
......@@ -90,6 +90,19 @@ class GeventLocalTestCase(greentest.TestCase):
with self.assertRaises(AttributeError):
del l.__dict__
def test_delete_with_no_dict(self):
l = local()
with self.assertRaises(AttributeError):
delattr(l, 'thing')
def del_local():
with self.assertRaises(AttributeError):
delattr(l, 'thing')
t = Thread(target=del_local)
t.start()
t.join()
def test_slot_and_type_attributes(self):
a = A(Obj())
a.initialized = 1
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment