Skip to content

Commit a136851

Browse files
committed
Also use parallelism to discover Python modules
1 parent f203262 commit a136851

1 file changed

Lines changed: 49 additions & 34 deletions

File tree

rust/src/graph/builder/mod.rs

Lines changed: 49 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use std::cmp::max;
12
use std::collections::{HashMap, HashSet};
23
use std::fs;
34
use std::path::PathBuf;
@@ -75,18 +76,13 @@ impl GraphBuilder {
7576
// Thread 1: Discover modules
7677
let package = self.package.clone();
7778
let handle = thread::spawn(move || {
78-
let modules = discover_python_modules(&package);
79-
// Send modules to parser threads
80-
for module in modules {
81-
module_discovery_sender.send(module).unwrap();
82-
}
83-
drop(module_discovery_sender); // Close channel to signal completion
79+
discover_python_modules(&package, module_discovery_sender);
8480
});
8581
thread_handles.push(handle);
8682

8783
// Thread pool: Parse imports
8884
let num_workers = thread::available_parallelism()
89-
.map(|n| n.get())
85+
.map(|n| max(n.get() / 2, 1))
9086
.unwrap_or(4);
9187
for _ in 0..num_workers {
9288
let receiver = module_discovery_receiver.clone();
@@ -151,11 +147,16 @@ struct ParsedModule {
151147
imported_objects: Vec<ImportedObject>,
152148
}
153149

154-
fn discover_python_modules(package: &PackageSpec) -> Vec<FoundModule> {
155-
let mut modules = Vec::new();
150+
fn discover_python_modules(package: &PackageSpec, sender: channel::Sender<FoundModule>) {
151+
let num_threads = thread::available_parallelism()
152+
.map(|n| max(n.get() / 2, 1))
153+
.unwrap_or(4);
154+
155+
let package_clone = package.clone();
156156

157-
let walker = WalkBuilder::new(&package.directory)
157+
WalkBuilder::new(&package.directory)
158158
.standard_filters(false) // Don't use gitignore or other filters
159+
.threads(num_threads)
159160
.filter_entry(|entry| {
160161
// Allow Python files
161162
if entry.file_type().is_some_and(|ft| ft.is_file()) {
@@ -170,31 +171,45 @@ fn discover_python_modules(package: &PackageSpec) -> Vec<FoundModule> {
170171

171172
false
172173
})
173-
.build();
174-
175-
for entry in walker.flatten() {
176-
let path = entry.path();
177-
if let Some(module_name) = path_to_module_name(path, package) {
178-
let is_package = is_package(path);
179-
180-
// Get mtime
181-
let mtime_secs = fs::metadata(path)
182-
.and_then(|m| m.modified())
183-
.ok()
184-
.and_then(|t| t.duration_since(std::time::UNIX_EPOCH).ok())
185-
.map(|d| d.as_secs() as i64)
186-
.unwrap_or(0);
187-
188-
modules.push(FoundModule {
189-
name: module_name,
190-
path: path.to_owned(),
191-
is_package,
192-
mtime_secs,
193-
});
194-
}
195-
}
174+
.build_parallel()
175+
.run(|| {
176+
let sender = sender.clone();
177+
let package = package_clone.clone();
178+
179+
Box::new(move |entry| {
180+
use ignore::WalkState;
181+
182+
let entry = match entry {
183+
Ok(e) => e,
184+
Err(_) => return WalkState::Continue,
185+
};
186+
187+
let path = entry.path();
188+
if let Some(module_name) = path_to_module_name(path, &package) {
189+
let is_package = is_package(path);
190+
191+
// Get mtime
192+
let mtime_secs = fs::metadata(path)
193+
.and_then(|m| m.modified())
194+
.ok()
195+
.and_then(|t| t.duration_since(std::time::UNIX_EPOCH).ok())
196+
.map(|d| d.as_secs() as i64)
197+
.unwrap_or(0);
198+
199+
let found_module = FoundModule {
200+
name: module_name,
201+
path: path.to_owned(),
202+
is_package,
203+
mtime_secs,
204+
};
205+
206+
// Send module as soon as we discover it
207+
let _ = sender.send(found_module);
208+
}
196209

197-
modules
210+
WalkState::Continue
211+
})
212+
});
198213
}
199214

200215
fn parse_module_imports(module: &FoundModule, cache: &ImportCache) -> Option<ParsedModule> {

0 commit comments

Comments
 (0)