Reduce lock contention (round 1)
- Use an async (i.e. unlimited buffer) MPSC channel instead of an Arc<Mutex<Vec>> for storing the scored matches in Sorter - Use Arc<Matcher> instead of Arc<Mutex<Matcher>> for the matcher, as it's not mutated and appears to be threadsafe. This cuts average iteration time (on the benchmarked machine) from 25.98ms to 16.08ms for the ivy_files benchmark.
This commit is contained in:
parent
ce28b248fa
commit
7fb8be541a
3 changed files with 26 additions and 17 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -5,3 +5,4 @@ compile_commands.json
|
|||
.luacheckcache
|
||||
benchmarks
|
||||
flamegraph*
|
||||
perf.data*
|
||||
|
|
|
|||
|
|
@ -66,18 +66,19 @@ pub extern "C" fn ivy_files(c_pattern: *const c_char, c_base_dir: *const c_char)
|
|||
}
|
||||
|
||||
pub fn inner_files(pattern: String, base_dir: String) -> String {
|
||||
// Bail out early if the pattern is empty its never going to find anything
|
||||
let mut output = String::new();
|
||||
|
||||
// Bail out early if the pattern is empty; it's never going to find anything
|
||||
if pattern.is_empty() {
|
||||
return String::new();
|
||||
return output;
|
||||
}
|
||||
|
||||
let files = get_files(&base_dir);
|
||||
|
||||
let mut output = String::new();
|
||||
let sorter_options = sorter::Options::new(pattern);
|
||||
|
||||
let files = sorter::sort_strings(sorter_options, files);
|
||||
for file in files.lock().unwrap().iter() {
|
||||
for file in files.iter() {
|
||||
output.push_str(&file.content);
|
||||
output.push('\n');
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
use super::matcher;
|
||||
use super::thread_pool;
|
||||
|
||||
use std::sync::mpsc;
|
||||
use std::sync::Arc;
|
||||
use std::sync::Mutex;
|
||||
|
||||
pub struct Match {
|
||||
pub score: i64,
|
||||
|
|
@ -23,30 +23,37 @@ impl Options {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn sort_strings(options: Options, strings: Vec<String>) -> Arc<Mutex<Vec<Match>>> {
|
||||
let matches: Arc<Mutex<Vec<Match>>> = Arc::new(Mutex::new(Vec::new()));
|
||||
let matcher = Arc::new(Mutex::new(matcher::Matcher::new(options.pattern)));
|
||||
pub fn sort_strings(options: Options, strings: Vec<String>) -> Vec<Match> {
|
||||
let mut matches = Vec::new();
|
||||
let matcher = Arc::new(matcher::Matcher::new(options.pattern));
|
||||
|
||||
let pool = thread_pool::ThreadPool::new(std::thread::available_parallelism().unwrap().get());
|
||||
|
||||
let (tx, rx) = mpsc::channel::<Match>();
|
||||
|
||||
for string in strings {
|
||||
let thread_matcher = Arc::clone(&matcher);
|
||||
let thread_matches = Arc::clone(&matches);
|
||||
let thread_transmitter = tx.clone();
|
||||
pool.execute(move || {
|
||||
let score = thread_matcher.lock().unwrap().score(string.to_string());
|
||||
let score = thread_matcher.score(string.to_string());
|
||||
if score > 25 {
|
||||
let mut tmp = thread_matches.lock().unwrap();
|
||||
let content = string.clone();
|
||||
tmp.push(Match { score, content });
|
||||
thread_transmitter
|
||||
.send(Match {
|
||||
score,
|
||||
content: string,
|
||||
})
|
||||
.expect("Failed to push data to channel");
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
drop(pool);
|
||||
drop(tx);
|
||||
|
||||
matches
|
||||
.lock()
|
||||
.unwrap()
|
||||
.sort_by(|a, b| a.score.cmp(&b.score));
|
||||
while let Ok(result) = rx.recv() {
|
||||
matches.push(result)
|
||||
}
|
||||
|
||||
matches.sort_by(|a, b| a.score.cmp(&b.score));
|
||||
matches
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue