]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
[3.14] gh-132657: avoid locks and refcounting in `frozenset` lookups (GH-136107)...
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>
Thu, 20 Nov 2025 01:00:42 +0000 (02:00 +0100)
committerGitHub <noreply@github.com>
Thu, 20 Nov 2025 01:00:42 +0000 (17:00 -0800)
gh-132657: avoid locks and refcounting in `frozenset` lookups (GH-136107)
(cherry picked from commit f58a7c717584241467970623384ce61cbd776f29)

Co-authored-by: Pieter Eendebak <pieter.eendebak@gmail.com>
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 83004e57b66c20796ffda831f1760107d1ff80dd..9332c24ac8673b3f7baf2f3fa47bd32787987a7d 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;
@@ -2234,10 +2243,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;
 }