Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improvement: Less GIL locking #197

Open
zwimer opened this issue Apr 27, 2022 · 3 comments
Open

Improvement: Less GIL locking #197

zwimer opened this issue Apr 27, 2022 · 3 comments

Comments

@zwimer
Copy link
Contributor

zwimer commented Apr 27, 2022

Binder currently seems to grab the GIL where not necessary. Here is an example:

struct PyCallBack_Annotation_Base : public Annotation::Base {
    using Annotation::Base::Base;

    bool eliminatable() const override {
        pybind11::gil_scoped_acquire gil;
        pybind11::function overload = pybind11::get_overload(static_cast<const Annotation::Base *>(this), "eliminatable");
        if (overload) {
            auto o = overload.operator()<pybind11::return_value_policy::reference>();
            if (pybind11::detail::cast_is_temporary_value_reference<bool>::value) {
                static pybind11::detail::override_caster_t<bool> caster;
                return pybind11::detail::cast_ref<bool>(std::move(o), caster);
            }
            else return pybind11::detail::cast_safe<bool>(std::move(o));
        }
        return Base::eliminatable();
    }
};

Notice that that return Base::eliminatable(); is influenced by pybind11::gil_scoped_acquire gil;; but if Annotation::Base().eliminatable is itself threadsafe this function should not need to be protected by the GIL. In that case, this can be modified in one of 2 ways:

  1. If binder does not need the GIL locked to do the logic before eliminatable() the GIL need not be acquired.
  2. If binder does require the GIL locked for those intermediate lines, it can be released before the return statement such as:
struct PyCallBack_Annotation_Base : public Annotation::Base {
    using Annotation::Base::Base;

    bool eliminatable() const override {
        { // Create a new scope
            pybind11::gil_scoped_acquire gil;
            pybind11::function overload = pybind11::get_overload(static_cast<const Annotation::Base *>(this), "eliminatable");
            if (overload) {
                auto o = overload.operator()<pybind11::return_value_policy::reference>();
                if (pybind11::detail::cast_is_temporary_value_reference<bool>::value) {
                    static pybind11::detail::override_caster_t<bool> caster;
                    return pybind11::detail::cast_ref<bool>(std::move(o), caster);
                }
                else return pybind11::detail::cast_safe<bool>(std::move(o));
            }
        } // Release GIL
        return Base::eliminatable();
    }
};
@zwimer zwimer changed the title Improvement: Extra GIL unlocking Improvement: Less GIL locking Apr 27, 2022
@lyskov
Copy link
Member

lyskov commented Apr 28, 2022

but if Annotation::Base().eliminatable is itself threadsafe this function should not need to be protected by the GIL

-- @zwimer could you please elaborate on this? Particularly why should we assume that Annotation::Base().eliminatable is threadsafe? The way i see it: it is indeed a C++ native call, but this does not mean it could be call some Python code inside (for example thorough a callback). Thanks,

@zwimer
Copy link
Contributor Author

zwimer commented Apr 28, 2022

Oh! My mistake, I misread the documentation in pybind11 to say the GIL is not held by default: https://pybind11.readthedocs.io/en/stable/advanced/misc.html?highlight=GIL#global-interpreter-lock-gil

In that case (perhaps this is better for a different issue?), would it be reasonable to feature request a 'do not hold the GIL' option in binder? Some libraries are designed to be thread-safe and do not need the GIL / actively do not want the GIL held. This could be a global option or a per-class / per-function / per-namespace option.

@lyskov
Copy link
Member

lyskov commented May 4, 2022

Interesting idea @zwimer ! I think this should be possible to do on the class level or/and namespace level. Let me think about how is it best to handle this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants