66//! This makes the total complexity `O(n³)`, however the calculation for each size is independent
77//! so we can parallelize over multiple threads.
88use crate :: util:: parse:: * ;
9+ use crate :: util:: thread:: * ;
910use std:: sync:: Mutex ;
10- use std:: thread;
1111
1212pub struct Result {
1313 x : usize ,
@@ -38,36 +38,15 @@ pub fn parse(input: &str) -> Vec<Result> {
3838 }
3939
4040 // Use as many cores as possible to parallelize the search.
41- let threads = thread:: available_parallelism ( ) . unwrap ( ) . get ( ) ;
41+ // Smaller sizes take more time so keep batches roughly the same effort so that some
42+ // threads are not finishing too soon and waiting idle, while others are still busy.
43+ // For example if there are 4 cores, then they will be assigned sizes:
44+ // * 1, 5, 9, ..
45+ // * 2, 6, 10, ..
46+ // * 3, 7, 11, ..
47+ // * 4, 8, 12, ..
4248 let mutex = Mutex :: new ( Vec :: new ( ) ) ;
43-
44- thread:: scope ( |scope| {
45- for i in 0 ..threads {
46- // Shadow references in local variables so that they can be moved into closure.
47- let sat = & sat;
48- let mutex = & mutex;
49-
50- // Smaller sizes take more time so keep batches roughly the same effort so that some
51- // threads are not finishing too soon and waiting idle, while others are still busy.
52- // For example if there are 4 cores, then they will be assigned sizes:
53- // * 1, 5, 9, ..
54- // * 2, 6, 10, ..
55- // * 3, 7, 11, ..
56- // * 4, 8, 12, ..
57- scope. spawn ( move || {
58- let batch: Vec < _ > = ( 1 + i..301 )
59- . step_by ( threads)
60- . map ( |size| {
61- let ( power, x, y) = square ( sat, size) ;
62- Result { x, y, size, power }
63- } )
64- . collect ( ) ;
65-
66- mutex. lock ( ) . unwrap ( ) . extend ( batch) ;
67- } ) ;
68- }
69- } ) ;
70-
49+ spawn_batches ( ( 1 ..301 ) . collect ( ) , |batch| worker ( batch, & sat, & mutex) ) ;
7150 mutex. into_inner ( ) . unwrap ( )
7251}
7352
@@ -81,6 +60,18 @@ pub fn part2(input: &[Result]) -> String {
8160 format ! ( "{x},{y},{size}" )
8261}
8362
63+ fn worker ( batch : Vec < usize > , sat : & [ i32 ] , mutex : & Mutex < Vec < Result > > ) {
64+ let result: Vec < _ > = batch
65+ . into_iter ( )
66+ . map ( |size| {
67+ let ( power, x, y) = square ( sat, size) ;
68+ Result { x, y, size, power }
69+ } )
70+ . collect ( ) ;
71+
72+ mutex. lock ( ) . unwrap ( ) . extend ( result) ;
73+ }
74+
8475/// Find the (x,y) coordinates and max power for a square of the specified size.
8576fn square ( sat : & [ i32 ] , size : usize ) -> ( i32 , usize , usize ) {
8677 let mut max_power = i32:: MIN ;
0 commit comments