Skip to content

Commit e02137e

Browse files
committed
Use deferred reference counting for threading primitives.
1 parent 96905bd commit e02137e

File tree

4 files changed

+61
-1
lines changed

4 files changed

+61
-1
lines changed

Lib/threading.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,11 @@
7373
_profile_hook = None
7474
_trace_hook = None
7575

76+
def _defer_refcount(op):
77+
"""Improve multithreaded scaling on the free-threade build."""
78+
if hasattr(_sys, "_defer_refcount"):
79+
_sys._defer_refcount(op)
80+
7681
def setprofile(func):
7782
"""Set a profile function for all threads started from the threading module.
7883
@@ -298,6 +303,7 @@ def __init__(self, lock=None):
298303
if hasattr(lock, '_is_owned'):
299304
self._is_owned = lock._is_owned
300305
self._waiters = _deque()
306+
_defer_refcount(self)
301307

302308
def _at_fork_reinit(self):
303309
self._lock._at_fork_reinit()
@@ -466,6 +472,7 @@ def __init__(self, value=1):
466472
raise ValueError("semaphore initial value must be >= 0")
467473
self._cond = Condition(Lock())
468474
self._value = value
475+
_defer_refcount(self)
469476

470477
def __repr__(self):
471478
cls = self.__class__
@@ -595,6 +602,7 @@ class Event:
595602
def __init__(self):
596603
self._cond = Condition(Lock())
597604
self._flag = False
605+
_defer_refcount(self)
598606

599607
def __repr__(self):
600608
cls = self.__class__
@@ -700,6 +708,7 @@ def __init__(self, parties, action=None, timeout=None):
700708
self._parties = parties
701709
self._state = 0 # 0 filling, 1 draining, -1 resetting, -2 broken
702710
self._count = 0
711+
_defer_refcount(self)
703712

704713
def __repr__(self):
705714
cls = self.__class__

Modules/_threadmodule.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -950,6 +950,7 @@ lock_new_impl(PyTypeObject *type)
950950
if (self == NULL) {
951951
return NULL;
952952
}
953+
_PyObject_SetDeferredRefcount((PyObject *)self);
953954
self->lock = (PyMutex){0};
954955
return (PyObject *)self;
955956
}
@@ -1221,6 +1222,7 @@ rlock_new_impl(PyTypeObject *type)
12211222
if (self == NULL) {
12221223
return NULL;
12231224
}
1225+
_PyObject_SetDeferredRefcount((PyObject *)self);
12241226
self->lock = (_PyRecursiveMutex){0};
12251227
return (PyObject *) self;
12261228
}

Python/clinic/sysmodule.c.h

Lines changed: 31 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Python/sysmodule.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ Data members:
1515
*/
1616

1717
#include "Python.h"
18+
#include "object.h"
1819
#include "pycore_audit.h" // _Py_AuditHookEntry
1920
#include "pycore_call.h" // _PyObject_CallNoArgs()
2021
#include "pycore_ceval.h" // _PyEval_SetAsyncGenFinalizer()
@@ -2653,6 +2654,23 @@ sys__is_gil_enabled_impl(PyObject *module)
26532654
#endif
26542655
}
26552656

2657+
/*[clinic input]
2658+
sys._defer_refcount -> bool
2659+
2660+
op: object
2661+
/
2662+
2663+
Defer reference counting for the object, allowing for better scaling across multiple threads.
2664+
2665+
This function should be used for specialized purposes only.
2666+
[clinic start generated code]*/
2667+
2668+
static int
2669+
sys__defer_refcount_impl(PyObject *module, PyObject *op)
2670+
/*[clinic end generated code: output=3b965122056085f5 input=a081971a76c49e64]*/
2671+
{
2672+
return PyUnstable_Object_EnableDeferredRefcount(op);
2673+
}
26562674

26572675
#ifndef MS_WINDOWS
26582676
static PerfMapState perf_map_state;
@@ -2834,6 +2852,7 @@ static PyMethodDef sys_methods[] = {
28342852
SYS__GET_CPU_COUNT_CONFIG_METHODDEF
28352853
SYS__IS_GIL_ENABLED_METHODDEF
28362854
SYS__DUMP_TRACELETS_METHODDEF
2855+
SYS__DEFER_REFCOUNT_METHODDEF
28372856
{NULL, NULL} // sentinel
28382857
};
28392858

0 commit comments

Comments
 (0)