Many Things at Once
● Advanced3 minBefore this: Tasks, Lists: map, filter, sumSpec 9.3
list.parallel_map(f, max: n) runs f on every item in tasks of their own, at most n at a time, and gives the results in the list's order.
fn square(n: Int) -> Int {
n * n
}
fn main() {
const results = [1, 2, 3, 4].parallel_map(n => square(n), max: 2)
print(results)
}The program ran and printed:
kavach run many.kav
[1, 4, 9, 16]The results come back in the list's order, whichever task finishes first. Here the later pages finish first, yet the list is in order:
use std.time
fn fetch(n: Int) -> String uses Clock {
time.sleep_ms(100 - n * 20)
"page {n}"
}
fn main() {
const pages = [1, 2, 3, 4].parallel_map(n => fetch(n), max: 4)
print(pages)
}The program ran and printed:
kavach run order.kav
["page 1", "page 2", "page 3", "page 4"]max keeps a program polite to a server: urls.parallel_map(download, max: 10) never has more than 10 downloads going at once. Without it, every task starts at once.
Each task runs as spawn thread makes it (How Tasks Run), so in a release build the items compute on several cores at once. In the benchmark, eight sums of 150 million rounds each take 210 ms with parallel_map — and 164 ms with plain map, because each of these sums is a math loop that already runs on all cores by itself. parallel_map is for items that can't spread themselves like that: downloads, files, work of uneven sizes.
When an item fails or panics
Given a function that can fail, parallel_map fails with the first error in the items' order. A panic in an item's task is printed when it happens, as any task's is, and is then a panic where parallel_map was called: the call can't fail by its type, so there is no error to give back.
fn main() {
print([4, 2].parallel_map(n => 8 / n))
print([4, 0, 2].parallel_map(n => 8 / n))
}[2, 4] panic: division by zero at src/main.kav:3 panic: an item of `parallel_map` panicked: division by zero at src/main.kav:3 at src/main.kav:3