]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-132657: avoid locks and refcounting in `frozenset` lookups (#136107)
authorPieter Eendebak <pieter.eendebak@gmail.com>
Sat, 30 Aug 2025 19:25:36 +0000 (21:25 +0200)
committerGitHub <noreply@github.com>
Sat, 30 Aug 2025 19:25:36 +0000 (00:55 +0530)
Misc/NEWS.d/next/Core_and_Builtins/2025-07-09-21-27-14.gh-issue-132657.kSA8R3.rst [new file with mode: 0644]
Objects/setobject.c

diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-07-09-21-27-14.gh-issue-132657.kSA8R3.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-07-09-21-27-14.gh-issue-132657.kSA8R3.rst
new file mode 100644 (file)
index 0000000..99f7a99
--- /dev/null
@@ -0,0 +1 @@
+Improve performance of :class:`frozenset` by removing locks in the free-threading build.
index 63ce55e236546f979cb513c6a0f7821b03faf4f8..d8340499be5aaea1c0a2464a48177aba3307ac8a 100644 (file)
@@ -86,6 +86,8 @@ set_lookkey(PySetObject *so, PyObject *key, Py_hash_t hash)
     int probes;
     int cmp;
 
+    int frozenset = PyFrozenSet_CheckExact(so);
+
     while (1) {
         entry = &so->table[i];
         probes = (i + LINEAR_PROBES <= mask) ? LINEAR_PROBES: 0;
@@ -102,13 +104,20 @@ set_lookkey(PySetObject *so, PyObject *key, Py_hash_t hash)
                     && unicode_eq(startkey, key))
                     return entry;
                 table = so->table;
-                Py_INCREF(startkey);
-                cmp = PyObject_RichCompareBool(startkey, key, Py_EQ);
-                Py_DECREF(startkey);
-                if (cmp < 0)
-                    return NULL;
-                if (table != so->table || entry->key != startkey)
-                    return set_lookkey(so, key, hash);
+                if (frozenset) {
+                    cmp = PyObject_RichCompareBool(startkey, key, Py_EQ);
+                    if (cmp < 0)
+                        return NULL;
+                } else {
+                    // incref startkey because it can be removed from the set by the compare
+                    Py_INCREF(startkey);
+                    cmp = PyObject_RichCompareBool(startkey, key, Py_EQ);
+                    Py_DECREF(startkey);
+                    if (cmp < 0)
+                        return NULL;
+                    if (table != so->table || entry->key != startkey)
+                        return set_lookkey(so, key, hash);
+                }
                 if (cmp > 0)
                     return entry;
                 mask = so->mask;
@@ -2235,10 +2244,16 @@ set_contains_lock_held(PySetObject *so, PyObject *key)
 int
 _PySet_Contains(PySetObject *so, PyObject *key)
 {
+    assert(so);
+
     int rv;
-    Py_BEGIN_CRITICAL_SECTION(so);
-    rv = set_contains_lock_held(so, key);
-    Py_END_CRITICAL_SECTION();
+    if (PyFrozenSet_CheckExact(so)) {
+        rv = set_contains_lock_held(so, key);
+    } else {
+        Py_BEGIN_CRITICAL_SECTION(so);
+        rv = set_contains_lock_held(so, key);
+        Py_END_CRITICAL_SECTION();
+    }
     return rv;
 }