Add benchmark for Python threaded word count

Add benchmark where the sequential Rust version of the word count is
executed twice to demonstrate parallelism with Python threads.  Also
slightly simplify the benchmark functions.
This commit is contained in:
Alexander Niederbühl 2020-06-05 20:22:20 +02:00
parent bafe269dde
commit d2c7645bad
3 changed files with 42 additions and 14 deletions

View File

@ -7,21 +7,22 @@ use rayon::prelude::*;
/// Searches for the word, parallelized by rayon
#[pyfunction]
fn search(py: Python<'_>, contents: &str, needle: &str) -> PyResult<usize> {
let count = py.allow_threads(move || {
contents
.par_lines()
.map(|line| count_line(line, needle))
.sum()
});
Ok(count)
fn search(contents: &str, needle: &str) -> usize {
contents
.par_lines()
.map(|line| count_line(line, needle))
.sum()
}
/// Searches for a word in a classic sequential fashion
#[pyfunction]
fn search_sequential(contents: &str, needle: &str) -> PyResult<usize> {
let result = contents.lines().map(|line| count_line(line, needle)).sum();
Ok(result)
fn search_sequential(contents: &str, needle: &str) -> usize {
contents.lines().map(|line| count_line(line, needle)).sum()
}
#[pyfunction]
fn search_sequential_allow_threads(py: Python, contents: &str, needle: &str) -> usize {
py.allow_threads(|| search_sequential(contents, needle))
}
fn matches(word: &str, needle: &str) -> bool {
@ -56,6 +57,7 @@ fn count_line(line: &str, needle: &str) -> usize {
fn word_count(_py: Python<'_>, m: &PyModule) -> PyResult<()> {
m.add_wrapped(wrap_pyfunction!(search))?;
m.add_wrapped(wrap_pyfunction!(search_sequential))?;
m.add_wrapped(wrap_pyfunction!(search_sequential_allow_threads))?;
Ok(())
}

View File

@ -1,7 +1,8 @@
# -*- coding: utf-8 -*-
import os
from concurrent.futures import ThreadPoolExecutor
import pytest
import word_count
current_dir = os.path.abspath(os.path.dirname(__file__))
@ -49,3 +50,23 @@ def test_word_count_rust_sequential(benchmark, contents):
def test_word_count_python_sequential(benchmark, contents):
count = benchmark(word_count.search_py, contents, "is")
assert count == 10000
def run_rust_sequential_twice(
executor: ThreadPoolExecutor, contents: str, needle: str
) -> int:
future_1 = executor.submit(
word_count.search_sequential_allow_threads, contents, needle
)
future_2 = executor.submit(
word_count.search_sequential_allow_threads, contents, needle
)
result_1 = future_1.result()
result_2 = future_2.result()
return result_1 + result_2
def test_word_count_rust_sequential_twice_with_threads(benchmark, contents):
executor = ThreadPoolExecutor(max_workers=2)
count = benchmark(run_rust_sequential_twice, executor, contents, "is")
assert count == 20000

View File

@ -1,6 +1,11 @@
from .word_count import search, search_sequential
from .word_count import search, search_sequential, search_sequential_allow_threads
__all__ = ["search_py", "search", "search_sequential"]
__all__ = [
"search_py",
"search",
"search_sequential",
"search_sequential_allow_threads",
]
def search_py(contents, needle):