diff --git a/.github/workflows/benchmark_pr.yml b/.github/workflows/benchmark_pr.yml index c8722bcf..4747d138 100644 --- a/.github/workflows/benchmark_pr.yml +++ b/.github/workflows/benchmark_pr.yml @@ -8,9 +8,5 @@ jobs: steps: - uses: MilesCranmer/AirspeedVelocity.jl@action-v1 with: - julia-version: "1" tune: "true" - # Post to "summary" tab of workflow run: - job-summary: "true" - # Run benchmark using PR's version of the script: bench-on: ${{ github.event.pull_request.head.sha }} diff --git a/CHANGELOG.md b/CHANGELOG.md index 2f9ff76f..6957e678 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,10 @@ # Changelog ## Unreleased - * Add configuration via Preferences in addition to environment variables (e.g. `exe` rather than `JULIA_PYTHONCALL_EXE`.) +* Internals: removed the cache of unused Python objects. This makes `pydel!` faster and + removes a race condition in free-threaded python. ## 0.9.32 (2026-05-14) * Added `juliacall.TypeValue.__numpy_dtype__` attribute to allow converting Julia types diff --git a/src/Core/Py.jl b/src/Core/Py.jl index 8b26f036..9c73a12a 100644 --- a/src/Core/Py.jl +++ b/src/Core/Py.jl @@ -37,8 +37,6 @@ decref(x::Py) = Base.GC.@preserve x (decref(getptr(x)); x) Base.unsafe_convert(::Type{C.PyPtr}, x::Py) = getptr(x) -const PYNULL_CACHE = Py[] - """ pynew([ptr]) @@ -50,12 +48,7 @@ points at, i.e. the new `Py` object owns a reference. Note that NULL Python objects are not safe in the sense that most API functions will probably crash your Julia session if you pass a NULL argument. """ -pynew() = - if isempty(PYNULL_CACHE) - Py(Val(:new), C.PyNULL) - else - pop!(PYNULL_CACHE) - end +pynew() = Py(Val(:new), C.PyNULL) const PyNULL = pynew() @@ -86,13 +79,10 @@ DANGER! Use this function ONLY IF the Julia object `x` could have been garbage-c anyway, i.e. was about to become unreachable. This means you MUST KNOW that no other part of the program has the Julia object `x`. -This decrements the reference count, sets the pointer to NULL and appends `x` to a cache -of unused objects (`PYNULL_CACHE`). +This decrements the reference count and sets the pointer to NULL. -This is an optimization to avoid excessive allocation and deallocation in Julia, which can -be a significant source of slow-down in code which uses a lot of Python objects. It allows -`pynew()` to pop an item from `PYNULL_CACHE` instead of allocating one, and avoids calling -the relatively slow finalizer on `x`. +Use this to eagerly free a Python object, rather than waiting for Julia's GC to finalize +it at some indeterminate point in the future. """ function pydel!(x::Py) ptr = getptr(x) @@ -100,7 +90,6 @@ function pydel!(x::Py) C.Py_DecRef(ptr) setptr!(x, C.PyNULL) end - push!(PYNULL_CACHE, x) return end