use goish::prelude::*;
#[derive(Clone, Default)]
struct Job { id: int, n: int }
fmt::stringer! {
impl Job {
fn String(&self) -> string {
fmt::Sprintf!("Job#%d(n=%d)", self.id, self.n)
}
}
}
#[derive(Clone, Default)]
#[allow(dead_code)]
struct Result { job_id: int, square: int, worker: int }
fn worker(id: int, jobs: Chan<Job>, results: Chan<Result>) {
defer!{ fmt::Printf!("worker %d: shutting down\n", id); }
loop {
let (job, _) = jobs.Recv();
if job.id < 0 { return; }
time::Sleep(time::Millisecond * 20i64);
let r = Result { job_id: job.id, square: job.n * job.n, worker: id };
results.Send(r);
}
}
fn main() {
let args = os::Args();
let n_jobs: int = if args.len() >= 2 {
let (n, err) = strconv::Atoi(&args[1]);
if err != nil {
fmt::Println!("bad arg:", err);
os::Exit(1);
}
n
} else { 6 };
fmt::Printf!("running %d jobs across 3 workers...\n", n_jobs);
let start = time::Now();
let jobs: Chan<Job> = chan!(Job, 16);
let results: Chan<Result> = chan!(Result, 16);
let mut handles: slice<Goroutine> = make!([]Goroutine, 0, 3);
for w in 1i64..=3 {
let j = jobs.clone();
let r = results.clone();
handles.push(go!{ worker(w, j, r); });
}
for i in 1i64..=n_jobs {
jobs.Send(Job { id: i, n: i + 10 });
}
for _ in 0..3 {
jobs.Send(Job { id: -1, n: 0 }); }
let mut by_worker: map<int, slice<int>> = make!(map[int]slice<int>);
for _ in 0..n_jobs {
let (r, _) = results.Recv();
let entry = by_worker.entry(r.worker).or_insert_with(|| slice::<int>::new());
entry.push(r.square);
}
for g in handles { let _ = g.Wait(); }
fmt::Println!();
fmt::Println!("results by worker:");
let mut worker_ids: slice<&int> = by_worker.keys().collect();
worker_ids.sort();
for (_, wid) in range!(worker_ids) {
let squares = &by_worker[*wid];
let as_strs: slice<string> = squares.iter().map(|n| strconv::Itoa(*n)).collect();
fmt::Printf!(" worker %d: %d squares [%s]\n",
**wid, len!(squares), strings::Join(&as_strs, ", "));
}
let elapsed = time::Since(start);
fmt::Printf!("\nfinished in %s\n", elapsed);
}