Skip to content

Commit

Permalink
feat: free-threaded pybind11
Browse files Browse the repository at this point in the history
Signed-off-by: Henry Schreiner <[email protected]>
  • Loading branch information
henryiii committed Jun 30, 2024
1 parent 7cc8622 commit 8db83f4
Show file tree
Hide file tree
Showing 5 changed files with 67 additions and 2 deletions.
5 changes: 4 additions & 1 deletion projects/hello-free-threading/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,7 @@ find_package(

python_add_library(_core MODULE src/freecomputepi/_core.cpp WITH_SOABI)

install(TARGETS _core DESTINATION freecomputepi)
find_package(pybind11 REQUIRED)
pybind11_add_module(_pybcore MODULE src/freecomputepi/_pybcore.cpp)

install(TARGETS _core _pybcore DESTINATION freecomputepi)
2 changes: 1 addition & 1 deletion projects/hello-free-threading/pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[build-system]
requires = ["scikit-build-core >=0.9.5"]
requires = ["scikit-build-core >=0.9.5", "pybind11 >=2.13.1"]
build-backend = "scikit_build_core.build"

[project]
Expand Down
25 changes: 25 additions & 0 deletions projects/hello-free-threading/src/freecomputepi/_pybcore.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#include <pybind11/pybind11.h>
#include <random>

namespace py = pybind11;

double pi(int n) {
double sum = 0.0;

std::random_device r;
std::default_random_engine e1(r());
std::uniform_real_distribution<double> uniform_dist(-1, 1);

for (int i = 0; i < n; i++) {
double x = uniform_dist(e1);
double y = uniform_dist(e1);
if (x * x + y * y <= 1.0) {
sum += 1.0;
}
}
return 4.0 * sum / n;
}

PYBIND11_MODULE(_pybcore, m, py::mod_gil_not_used()) {
m.def("pi", &pi);
}
30 changes: 30 additions & 0 deletions projects/hello-free-threading/src/freecomputepi/pybind.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import argparse
import statistics
import time
from concurrent.futures import ThreadPoolExecutor

from ._pybcore import pi


def pi_in_threads(threads: int, trials: int) -> float:
if threads == 0:
return pi(trials)
with ThreadPoolExecutor(max_workers=threads) as executor:
return statistics.mean(executor.map(pi, [trials // threads] * threads))


def main() -> None:
parser = argparse.ArgumentParser()
parser.add_argument("--threads", type=int, default=0)
parser.add_argument("--trials", type=int, default=100_000_000)
args = parser.parse_args()

start = time.monotonic()
π = pi_in_threads(args.threads, args.trials)
stop = time.monotonic()

print(f"{args.trials} trials, {π = }, {stop - start:.4} s")


if __name__ == "__main__":
main()
7 changes: 7 additions & 0 deletions projects/hello-free-threading/tests/test_thread.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import freecomputepi.comp
import freecomputepi.pure
import freecomputepi.pybind
import pytest


Expand All @@ -13,3 +14,9 @@ def test_pure(threads):
def test_comp(threads):
π = freecomputepi.comp.pi_in_threads(threads, 100_000_000)
assert π == pytest.approx(3.1415926535, rel=0.01)


@pytest.mark.parametrize("threads", [0, 1, 2, 4])
def test_pybind(threads):
π = freecomputepi.pybind.pi_in_threads(threads, 100_000_000)
assert π == pytest.approx(3.1415926535, rel=0.01)

0 comments on commit 8db83f4

Please sign in to comment.