@@ -5,7 +5,7 @@ use std::{
5
5
io:: { self , Read , Seek , StdoutLock , Write } ,
6
6
path:: { Path , MAIN_SEPARATOR_STR } ,
7
7
process:: { Command , Stdio } ,
8
- sync:: mpsc,
8
+ sync:: { atomic :: AtomicUsize , mpsc, Arc } ,
9
9
thread,
10
10
} ;
11
11
@@ -20,6 +20,7 @@ use crate::{
20
20
} ;
21
21
22
22
const STATE_FILE_NAME : & str = ".rustlings-state.txt" ;
23
+ const DEFAULT_CHECK_PARALLELISM : usize = 8 ;
23
24
24
25
#[ must_use]
25
26
pub enum ExercisesProgress {
@@ -411,17 +412,31 @@ impl AppState {
411
412
412
413
let ( mut checked_count, mut results) = thread:: scope ( |s| {
413
414
let ( tx, rx) = mpsc:: channel ( ) ;
414
-
415
- self . exercises
416
- . iter ( )
417
- . enumerate ( )
418
- . for_each ( |( index, exercise) | {
419
- let tx = tx. clone ( ) ;
420
- let cmd_runner = & self . cmd_runner ;
421
- let _ = thread:: Builder :: new ( ) . spawn_scoped ( s, move || {
422
- tx. send ( ( index, exercise. run_exercise ( None , cmd_runner) ) )
423
- } ) ;
415
+ let exercise_ind = Arc :: new ( AtomicUsize :: default ( ) ) ;
416
+
417
+ let num_core = thread:: available_parallelism ( )
418
+ . map_or ( DEFAULT_CHECK_PARALLELISM , |count| count. get ( ) ) ;
419
+ ( 0 ..num_core) . for_each ( |_| {
420
+ let tx = tx. clone ( ) ;
421
+ let exercise_ind = exercise_ind. clone ( ) ;
422
+ let this = & self ;
423
+ let _ = thread:: Builder :: new ( ) . spawn_scoped ( s, move || {
424
+ loop {
425
+ let exercise_ind =
426
+ exercise_ind. fetch_add ( 1 , std:: sync:: atomic:: Ordering :: AcqRel ) ;
427
+ let Some ( exercise) = this. exercises . get ( exercise_ind) else {
428
+ // No more exercises
429
+ break ;
430
+ } ;
431
+ if tx
432
+ . send ( ( exercise_ind, exercise. run_exercise ( None , & this. cmd_runner ) ) )
433
+ . is_err ( )
434
+ {
435
+ break ;
436
+ }
437
+ }
424
438
} ) ;
439
+ } ) ;
425
440
426
441
// Drop this `tx`, since the `rx` loop will not stop while there is
427
442
// at least one tx alive (i.e. we want the loop to block only while
0 commit comments