-
-
Save elimisteve/4442820 to your computer and use it in GitHub Desktop.
// Steve Phillips / elimisteve | |
// 2013.01.03 | |
// Programming Challenge: Launch 4 threads, goroutines, coroutines, or whatever your language uses for concurrency, | |
// in addition to the main thread. In the first 3, add numbers together (see sample code below) and pass the results | |
// to the 4th thread. That 4th thread should receive the 3 results, add the numbers together, format the results as | |
// a string (see sample code), and pass the result back to `main` to be printed. | |
// | |
// Do this as succinctly and readably as possible. _Go!_ #golang #programming #concurrency #challenge | |
package main | |
import "fmt" | |
// intDoubler doubles the given int, then sends it through the given channel | |
func intDoubler(ch chan int, n int) { | |
ch <- n*2 | |
} | |
func main() { | |
// Make channel of ints | |
ch := make(chan int) | |
answer := make(chan string) | |
// Spawn 3 goroutines (basically threads) to process data in background | |
go intDoubler(ch, 10) | |
go intDoubler(ch, 20) | |
go func(a, b int) { ch <- a+b }(30, 40) // Take 2 ints, write sum to `ch` | |
// Create anonymous function on the fly, launch as goroutine! | |
go func() { | |
// Save the 3 values passed through the channel as x, y, and z | |
x, y, z := <-ch, <-ch, <-ch | |
// Calculate answer, write to `answer` channel | |
answer <- fmt.Sprintf("%d + %d + %d = %d", x, y, z, x+y+z) | |
}() | |
// Print answer resulting from channel read | |
fmt.Printf("%s\n", <-answer) | |
} |
Another Clojure example, this time with a bit of macro meta-programming to give us a beautiful syntax:
(defmacro go [& body] `@(future ~@body))
(go (+ (go (* 2 10))
(go (* 2 20))
(go (+ 30 40))))
You're really missing a Scala example.
import concurrent.Future
for (a <- Future { 2 * 10 };
b <- Future { 2 * 20 };
c <- Future { 30 + 40 };
sum <- Future { a + b + c })
{ println(s"$a + $b + $c = $sum") }
That's pretty readable.
And the console output:
scala> :paste
// Entering paste mode (ctrl-D to finish)
for (a <- Future { 2 * 10 };
b <- Future { 2 * 20 };
c <- Future { 30 + 40 };
sum <- Future { a + b + c })
{ println(s"$a + $b + $c = $sum") }
// Exiting paste mode, now interpreting.
scala> 20 + 40 + 70 = 130
C, written in an archaic style, likely would work on an early UNIX system.
#include <sys/wait.h>
#include <stdio.h>
#include <unistd.h>
int intDoubler(i)
int i;
{
return i * 2;
}
int intAdder2(i, j)
int i, j;
{
return i + j;
}
int intAdder3(i, j, k)
int i, j, k;
{
return i + j + k;
}
int main(argc, argv)
int argc;
char *argv[];
{
int answer;
int i, j, k;
switch (fork()) {
case 0:
switch (fork()) {
case 0:
return intDoubler(10);
default:
break;
}
switch (fork()) {
case 0:
return intDoubler(20);
default:
break;
}
switch (fork()) {
case 0:
return intAdder2(30, 40);
default:
break;
}
wait(&i);
wait(&j);
wait(&k);
return intAdder3(WEXITSTATUS(i), WEXITSTATUS(j), WEXITSTATUS(k));
default:
wait(&answer);
printf("%d\n", WEXITSTATUS(answer));
break;
}
return 0;
}
Here is nearly verbatim copy of the go source into haskell:
import Control.Monad
import Control.Concurrent
import Control.Concurrent.Chan
import Text.Printf
double :: Chan Int -> Int -> IO ()
double ch n = writeChan ch (n*2)
main = do
ch <- newChan
answer <- newChan
forkIO $ double ch 10
forkIO $ double ch 20
forkIO $ (\a b -> writeChan ch (a + b)) 30 40
forkIO $ do
[x, y, z] <- replicateM 3 $ readChan ch
writeChan answer $ (printf "%d + %d + %d = %d" x y z (x+y+z) :: String)
printf "%s\n" =<< readChan answer
Haskell, using monad-par:
module Main where
import Control.Monad
import Control.Monad.Par
import Text.Printf
-- | some common boilerplate
defer :: (NFData a) => Par a -> Par (Par a)
defer = liftM get . spawn
deferP :: (NFData a) => a -> Par (Par a)
deferP = liftM get . spawnP
calc :: Par String
calc = do
pa <- deferP (2 * 10 :: Int)
pb <- deferP (2 * 20)
pc <- deferP (30 + 40)
-- pc <- defer $ liftM2 (+) pa pb -- this is a mildly more exiting use case
liftM3 summary pa pb pc
where
summary a b c = printf "%d + %d + %d = %d" a b c (a+b+c)
main = do
print (runPar calc)
hi is the following a valid solution?
package main
import "fmt"
import "strconv"
/*
Programming Challenge: Launch 4 threads, goroutines, coroutines, or whatever your language uses for concurrency,
in addition to the main thread. In the first 3, add numbers together (see sample code below) and pass the results
to the 4th thread. That 4th thread should receive the 3 results, add the numbers together, format the results as a
string (see sample code), and pass the result back to main
to be printed. Do this as succinctly and readably as
possible. Go! #golang #programming #concurrency #challenge
*/
func intToString(input_num int) string {
return strconv.FormatInt(int64(input_num), 10)
}
func intDoubler(a int, res chan int) {
res <- a * 2
}
func addInts(a int, b int, res chan int) {
res <- a + b
}
func formatFinal(res chan int, final chan string) {
var sum int
for i := 0; i<3; i++ {
sum += <-res
}
final <- intToString(sum)
}
func main() {
intChan := make(chan int, 3)
strChan := make(chan string)
go intDoubler(10, intChan)
go intDoubler(20, intChan)
go addInts(30, 40, intChan)
go formatFinal(intChan, strChan)
res := <-strChan
fmt.Println(res)
}
Challenge accepted :)
PHP: https://gist.github.com/polonskiy/6b21065008c21170d9d6
Rust 1.3 solution (looks like the earlier Rust solutions are outdated)
use std::thread;
fn main() {
let mut children = vec![];
children.push(thread::spawn(move || {10*2}));
children.push(thread::spawn(move || {20*2}));
children.push(thread::spawn(move || {30+40}));
let adder = thread::spawn(move || {
let mut sum = 0;
let result = children.into_iter().map(|child| {
let value = child.join().unwrap();
sum += value;
format!("{}", value)
}).collect::<Vec<_>>().join(" + ");
return format!("{} = {}", result, sum);
});
let result = adder.join().unwrap();
println!("{}", result);
}
@polonskiy Actually, I'm not even mad! That's amazing 😨
Would be interesting to see this done with http://libmill.org/ !
Mozart/Oz: