PERF `PairwiseDistancesReductions` subsequent work

`PairwiseDistancesReductions` have been introduced as a hierarchy of Cython classes to implement back-ends of some scikit-learn algorithms.

Initial work was listed in #22587.

:bulb: See [this presentation](https://docs.google.com/presentation/d/1RwX_P9lnsb9_YRZ0cA88l3VoEYhiMndQYoKLLF_0Dv0/edit?usp=sharing) for a better understanding of the design of `PairwiseDistancesReductions`.

:bulb: **Before working on improving performance, one must profile the current execution of algorithms to see if there are any substantial benefits.**

Subsequent possible work includes:

 - [ ] #26983 
 - [ ] #25097
 - [ ] Support `"precomputed"` distances
 - Implement back-end for other `Estimators` or `Transformers`, in particular, introduce a specialised back-end for which would remove the costly sequential portion around the current call to `kneighbors` or `radius_neighbors` for (non-complete list):
 	- [ ] computing the MST from the data matrix (`mst_from_data_matrix`) see https://github.com/scikit-learn/scikit-learn/pull/25656#pullrequestreview-1326267314
 	- [ ] computing the MST linkage ([`mst_linkage_core`](https://github.com/scikit-learn/scikit-learn/blob/2ab1d81e167512719b6272d4ddf286bba5d3d232/sklearn/cluster/_hierarchical_fast.pyx#L428-L506))
 	- [x] `LocalOutlierFactor` ([no further optimization possible](https://github.com/scikit-learn/scikit-learn/pull/26316))
 	- [ ] `KNeighbors*.predict*`
 	   - [x] #24076 by @Micky774
 	   - [ ] #28219 by @OmarManzoor
 	   - [ ] Implement multi-output support (WIP [here](https://github.com/Micky774/scikit-learn/pull/3))
 	   - [ ] Support `"distance"` weighting
 	- [ ] `RadiusNeighbors*.predict*`
 	   - [x] #26828
 	   - [ ] Implement Euclidean specialization
 	   - [ ] Implement multi-output support
 	   - [ ] Support `"distance"` weighting
 	- some part of `KMeans`
 - [ ] Force the use of `PairwiseDistancesReductions` for F-contiguous arrays
   - use a scikit-learn configuration entry to accept and convert F-contiguous arrays to C-contiguous arrays
 - [ ] Release the GIL before calling `parallel_on_{X|Y}` instead of releasing it in those methods
    - :bulb: I once have tried and I don't think this is possible.
 - [ ] Integrate `mimalloc` to have proper memory allocation for multi-threaded implementations:
    - :bulb: Changing the default implementation of `malloc(1)` might come with unexpected changes and might break the whole ecosystem. Also maintaining it might be costly.
 - [ ] Tests improvements ideas:
   - https://github.com/scikit-learn/scikit-learn/pull/27281#issuecomment-1704334881
   - parametrize old tests for public API backed by `PairwiseDistancesReductions`?
   - systematically test public API on combinations of sparse and dense datasets?
 - [ ] Extend this design for a new back-end for [`pairwise_kernels`](https://github.com/scikit-learn/scikit-learn/blob/7d1c31892d34e6456c467c3d538ecb0ec4e01c35/sklearn/metrics/pairwise.py#L2116)-based interfaces

COMMENT:
@jjerphan @Micky774 

I was not able to successfully run py-spy but using some simple timeit statements I was able to get the following results
```
--------------------------Iteration 1--------------------------
Start predict probabilities
Time taken by radius_neighbors: 19.6450375
Time taken to compute probabilities: 36.3680472
-----------------------------------------------------------------
--------------------------Iteration 2--------------------------
Start predict probabilities
Time taken by radius_neighbors: 39.5624981
Time taken to compute probabilities: 44.52882960000001
-----------------------------------------------------------------
--------------------------Iteration 3--------------------------
Start predict probabilities
Time taken by radius_neighbors: 29.812655099999972
Time taken to compute probabilities: 43.69632340000004
-----------------------------------------------------------------
```

And two more iterations in which I ran the complete script again including the fit method.
```
Time taken by radius_neighbors: 32.9073425
Time taken to compute probabilities: 42.0797534
---------------------------------------------------------------
Start predict probabilities
Time taken by radius_neighbors: 16.559098600000002
Time taken to compute probabilities: 36.1868528
```

Code
<Details>

```python
from sklearn.model_selection import train_test_split
from sklearn.neighbors._classification import RadiusNeighborsClassifier
from sklearn.datasets import make_classification


n_features = 10
n_samples = 50000
n_classes = 100

X, y = make_classification(
    n_samples=n_samples,
    n_features=n_features,
    n_redundant=0,
    n_informative=10,
    n_classes=n_classes,
    random_state=0,
)


X_train, X_test, y_train, _ = train_test_split(X, y, random_state=0)
clf = RadiusNeighborsClassifier(radius=10, algorithm="brute")
clf.fit(X_train, y_train)
for i in range(1, 6):
    print(f"--------------------------Iteration {i}--------------------------")
    print("Start predict probabilities")
    proba = clf.predict_proba(X_test)
    print("-----------------------------------------------------------------")

```
</Details>

Labels: Performance, cython, Meta-issue