Skip to content

Commit fbda041

Browse files
committed
make lock with fine-grianed
1 parent ed73c90 commit fbda041

2 files changed

Lines changed: 107 additions & 0 deletions

File tree

Objects/typeobject.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6546,6 +6546,18 @@ type_setattro(PyObject *self, PyObject *name, PyObject *value)
65466546
assert(!_PyType_HasFeature(metatype, Py_TPFLAGS_INLINE_VALUES));
65476547
assert(!_PyType_HasFeature(metatype, Py_TPFLAGS_MANAGED_DICT));
65486548

6549+
#ifdef Py_GIL_DISABLED
6550+
if (value != NULL && PyFunction_Check(value)) {
6551+
if (!_PyObject_HasDeferredRefcount(value)) {
6552+
BEGIN_TYPE_LOCK();
6553+
if (!_PyObject_HasDeferredRefcount(value)) {
6554+
PyUnstable_Object_EnableDeferredRefcount(value);
6555+
}
6556+
END_TYPE_LOCK();
6557+
}
6558+
}
6559+
#endif
6560+
65496561
PyObject *old_value = NULL;
65506562
PyObject *descr = _PyType_LookupRef(metatype, name);
65516563
if (descr != NULL) {
@@ -6573,6 +6585,7 @@ type_setattro(PyObject *self, PyObject *name, PyObject *value)
65736585
}
65746586
}
65756587

6588+
65766589
BEGIN_TYPE_DICT_LOCK(dict);
65776590
res = type_update_dict(type, (PyDictObject *)dict, name, value, &old_value);
65786591
assert(_PyType_CheckConsistency(type));

edward-test-bench.py

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
import _testcapi
2+
from threading import Thread
3+
from time import time
4+
5+
def test_1():
6+
class Foo:
7+
def __init__(self, x):
8+
self.x = x
9+
10+
niter = 5 * 1000 * 1000
11+
12+
def benchmark(n):
13+
for i in range(n):
14+
Foo(x=1)
15+
16+
for nth in (1, 4):
17+
t0 = time()
18+
threads = [Thread(target=benchmark, args=(niter,)) for _ in range(nth)]
19+
for t in threads:
20+
t.start()
21+
for t in threads:
22+
t.join()
23+
print(f"{nth=} {(time() - t0) / nth}")
24+
25+
def test_2():
26+
class Foo2:
27+
def __init__(self, x):
28+
pass
29+
pass
30+
31+
_Foo2_x = int
32+
33+
create_str = """def create_init(_Foo2_x,):
34+
def __init__(self, x: _Foo2_x):
35+
self.x = x
36+
return (__init__,)
37+
"""
38+
ns = {}
39+
exec(create_str, globals(), ns)
40+
fn = ns['create_init']({**locals()})
41+
setattr(Foo2, '__init__', fn[0])
42+
niter = 5 * 1000 * 1000
43+
def benchmark(n):
44+
for i in range(n):
45+
Foo2(x=1)
46+
47+
for nth in (1, 4):
48+
t0 = time()
49+
threads = [Thread(target=benchmark, args=(niter,)) for _ in range(nth)]
50+
for t in threads:
51+
t.start()
52+
for t in threads:
53+
t.join()
54+
print(f"{nth=} {(time() - t0) / nth}")
55+
56+
def test_3():
57+
class Foo3:
58+
def __init__(self, x):
59+
pass
60+
pass
61+
62+
_Foo3_x = int
63+
64+
create_str = """def create_init(_Foo3_x,):
65+
def __init__(self, x: _Foo3_x):
66+
self.x = x
67+
return (__init__,)
68+
"""
69+
ns = {}
70+
exec(create_str, globals(), ns)
71+
fn = ns['create_init']({**locals()})
72+
setattr(Foo3, '__init__', fn[0])
73+
_testcapi.pyobject_enable_deferred_refcount(Foo3.__init__)
74+
niter = 5 * 1000 * 1000
75+
def benchmark(n):
76+
for i in range(n):
77+
Foo3(x=1)
78+
79+
for nth in (1, 4):
80+
t0 = time()
81+
threads = [Thread(target=benchmark, args=(niter,)) for _ in range(nth)]
82+
for t in threads:
83+
t.start()
84+
for t in threads:
85+
t.join()
86+
print(f"{nth=} {(time() - t0) / nth}")
87+
88+
if __name__ == "__main__":
89+
print("------test_1-------")
90+
test_1()
91+
print("------test_2-------")
92+
test_2()
93+
print("------test_3-------")
94+
test_3()

0 commit comments

Comments
 (0)