Created
February 12, 2017 14:39
-
-
Save ybubnov/e83e00d3cf5d54139e4433ff5786843b to your computer and use it in GitHub Desktop.
Parallel conversion of the numbers to multiple radix
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"fmt" | |
"runtime" | |
"strconv" | |
"strings" | |
) | |
const ( | |
from = 2 | |
to = 36 | |
perline = 8 | |
value = uint64(35) | |
) | |
// min returns the smaller of a or b. | |
func min(a, b int) int { | |
if a < b { | |
return a | |
} | |
return b | |
} | |
// tuple grounps the target radix and the value to convert. | |
type tuple struct { | |
value uint64 | |
base int | |
} | |
// generator writes into the pipe channel a set of pairs of | |
// target radix plus the integer to convert. | |
func generator(from, to int, pipe chan<- tuple) { | |
defer close(pipe) | |
for from <= to { | |
pipe <- tuple{value, from} | |
from++ | |
} | |
} | |
// converter reads the specified number of the integers from | |
// the ch channel, convers them according to the configuration | |
// and puts the result into the pipe channel. | |
func converter(n int, ch <-chan tuple, pipe chan<- string) { | |
for i := 0; i < n; i++ { | |
c := <-ch | |
pipe <- strconv.FormatUint(c.value, c.base) | |
} | |
} | |
// reducer groups the converted numbers into the comma- | |
// separated chunks and sends them into the pipe channel. | |
func reducer(n int, ch <-chan string, pipe chan<- string) { | |
var line []string | |
for i := 0; i < n; i++ { | |
line = append(line, <-ch) | |
if len(line) == perline || i+1 == n { | |
pipe <- strings.Join(line, ", ") | |
line = nil | |
} | |
} | |
} | |
// dumper prints the specified amount of the received strings | |
// from the channel ch to the standard output. | |
func dumper(n int, ch <-chan string) <-chan struct{} { | |
done := make(chan struct{}) | |
go func() { | |
for i := 0; i < n; i++ { | |
fmt.Println(<-ch) | |
} | |
done <- struct{}{} | |
}() | |
return done | |
} | |
func main() { | |
// Spawn as much routines as number of CPUs are | |
// installed on the host (number can be less, | |
// and denepnds on the user inputs). | |
ncpu := runtime.NumCPU() | |
nconv := to - from + 1 | |
// The channels to pipeline the output from the | |
// different routines. | |
convert := make(chan tuple) | |
reduce := make(chan string) | |
dump := make(chan string) | |
// Generate the pairs: target radix, number to | |
// convert. | |
go generator(from, to, convert) | |
nwork := min(ncpu, nconv) | |
for i := 0; i < nwork; i++ { | |
// Each routine will be assigned to process | |
// equal amount of the numbers, except the | |
// first one, which takes additional load. | |
n := nconv / nwork | |
if i == 0 { | |
n += (nconv % nwork) | |
} | |
go converter(n, convert, reduce) | |
} | |
// When host provides more CPUs, than lines should | |
// be printed, the amount of workers is reduced to | |
// the number of lines to print (e.g. 1 for 2 CPUs). | |
nline := nconv / perline | |
if nconv%perline != 0 { | |
nline++ | |
} | |
nwork = min(ncpu, nline) | |
for i := 0; i < nwork; i++ { | |
// The reduce rountines have to print the even | |
// numbers of elements (per line). As in the | |
// previous algorithm, the first routine takes | |
// additional load. | |
n := perline * (nconv / perline / nwork) | |
if i == 0 { | |
n += (nconv - n*nwork) | |
} | |
go reducer(n, reduce, dump) | |
} | |
// Wait for the last routine, that prints the | |
// resulting comman-separated lines of numbers. | |
<-dumper(nline, dump) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment