diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-04-01-12-35-55.gh-issue-147985.YVirHJ.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-04-01-12-35-55.gh-issue-147985.YVirHJ.rst new file mode 100644 index 00000000000000..a94dfca5e2a498 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-04-01-12-35-55.gh-issue-147985.YVirHJ.rst @@ -0,0 +1,3 @@ +Make :c:func:`PySet_Contains` attempt a lock-free lookup, similar to +:meth:`!set.__contains__`. This avoids acquiring the set object mutex in the +normal case. diff --git a/Objects/setobject.c b/Objects/setobject.c index ae6c1d1248d2fc..1e630563604552 100644 --- a/Objects/setobject.c +++ b/Objects/setobject.c @@ -3023,14 +3023,14 @@ PySet_Contains(PyObject *anyset, PyObject *key) PyErr_BadInternalCall(); return -1; } - if (PyFrozenSet_CheckExact(anyset)) { - return set_contains_key((PySetObject *)anyset, key); + + PySetObject *so = (PySetObject *)anyset; + Py_hash_t hash = _PyObject_HashFast(key); + if (hash == -1) { + set_unhashable_type(key); + return -1; } - int rv; - Py_BEGIN_CRITICAL_SECTION(anyset); - rv = set_contains_key((PySetObject *)anyset, key); - Py_END_CRITICAL_SECTION(); - return rv; + return set_contains_entry(so, key, hash); } int