GeezerVisonThe World Wide Web, restored to 800 pixels of glory. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Home|About|Gaming cabinet|Archives|How it works|Starter sites | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
GeezerVison is showing github.com — Avoid stop-the-world when `__abstractmethods__` does not change the abstract flag · Issue #161744 · python/cpython Open Labels interpreter-core(Objects, Python, Grammar, and Parser dirs)(Objects, Python, Grammar, and Parser dirs)performancePerformance or resource usagePerformance or resource usagetopic-free-threadingtype-featureA feature request or enhancementA feature request or enhancement DescriptionSummaryIn a free-threaded CPython build,
Benchmarkimport argparse, gc, statistics, sys, threading, time, typing from abc import ABC, abstractmethod from collections.abc import Sized def make(kind, n): if kind == "concrete": for _ in range(n): class X(Sized): def __len__(self): return 0 elif kind == "protocol": for _ in range(n): class P(typing.Protocol): def m(self) -> int: ... class C(P): def m(self) -> int: return 0 elif kind == "abstract": for _ in range(n): class Y(ABC): @abstractmethod def m(self): ... elif kind == "plain": for _ in range(n): class Z: pass else: raise SystemExit(f"unknown kind {kind}") def one_round(kind, k, n): barrier = threading.Barrier(k + 1) def worker(): barrier.wait() make(kind, n) ts = [threading.Thread(target=worker) for _ in range(k)] for t in ts: t.start() barrier.wait() t0 = time.perf_counter() for t in ts: t.join() return time.perf_counter() - t0 def main(): ap = argparse.ArgumentParser() ap.add_argument("--kind", default="concrete") ap.add_argument("--threads", type=int, default=1) ap.add_argument("--n", type=int, default=2000) ap.add_argument("--repeat", type=int, default=5) ap.add_argument("--no-gc", action="store_true") a = ap.parse_args() if a.no_gc: gc.disable() make(a.kind, 50) per = [one_round(a.kind, a.threads, a.n) / (a.n * a.threads) * 1e6 for _ in range(a.repeat)] gil = getattr(sys, "_is_gil_enabled", lambda: True)() print(f"{a.kind},{a.threads},{a.n},{statistics.median(per):.2f},{min(per):.2f},{gil}") if __name__ == "__main__": main() Multiple threads run
ImplementationIn if (abstract != ((type->tp_flags & Py_TPFLAGS_IS_ABSTRACT) != 0)) { type_lock_prevent_release(&pinned); types_stop_world(); if (abstract) type_add_flags(type, Py_TPFLAGS_IS_ABSTRACT); else type_clear_flags(type, Py_TPFLAGS_IS_ABSTRACT); types_start_world(); type_lock_allow_release(&pinned); } Performance resultsEach result below is the median of five outer rounds. Each benchmark invocation
Linked PRsActivity
MetadataMetadataAssigneesLabelsinterpreter-core(Objects, Python, Grammar, and Parser dirs)(Objects, Python, Grammar, and Parser dirs)performancePerformance or resource usagePerformance or resource usagetopic-free-threadingtype-featureA feature request or enhancementA feature request or enhancement ProjectsMilestoneRelationshipsDevelopmentIssue actions | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| You are visitor 01402503 — GeezerVison does not store the pages you look up. Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required. |