Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
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 strin…
// Steve Phillips / elimisteve
// 2013.01.03
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)
}
@jeena

This comment has been minimized.

Show comment Hide comment
@jeena

jeena Jan 3, 2013

Especially your line 26 is nearly impossible to get more beautifull and being just a shitty erlang programmer I only came up with something like that:

% Jeena Paradies
% 2013-01-03

-module (doubler).
-export ([start/0, int_doubler/2, collector/2]).

% int_doubler doubles the given int, then sends it to the given process
int_doubler(X, Collector) ->
    Collector ! X * 2.

% collector collects the answers untill it gets 3, formats them and sends
% the string to the main process
collector(Answers, Main) ->
    % wait for a message form one of the int_doubler or the Plus processes
    receive
        N ->
            case Answers of
                [X, Y] -> % if we have already 2 then this is the last
                    Result = io_lib:format("~w + ~w + ~w = ~w~n", [X, Y, N, X + Y + N]),
                    Main ! lists:flatten(Result);
                _ -> collector(Answers ++ [N], Main)
            end
    end.

start() ->
    % spawn one process to collect the data
    Collector = spawn(?MODULE, collector, [[], self()]),

    % spawn 3 processes to process data in background
    spawn(?MODULE, int_doubler, [10, Collector]),
    spawn(?MODULE, int_doubler, [20, Collector]),
    Plus = fun (A, B) -> Collector ! A + B end,
    spawn(fun() -> Plus(10, 22) end),

    % wait for a message from the collector process and print it
    receive
        Result -> io:format("~s", [Result])
    end.

I don't have the distinction between chanels and threads/goroutines, everything is just a process and every process can send messages to other processes. In the end I assume one would do stuff like that in a general way with OTP's gen_fsm or something similar.

jeena commented Jan 3, 2013

Especially your line 26 is nearly impossible to get more beautifull and being just a shitty erlang programmer I only came up with something like that:

% Jeena Paradies
% 2013-01-03

-module (doubler).
-export ([start/0, int_doubler/2, collector/2]).

% int_doubler doubles the given int, then sends it to the given process
int_doubler(X, Collector) ->
    Collector ! X * 2.

% collector collects the answers untill it gets 3, formats them and sends
% the string to the main process
collector(Answers, Main) ->
    % wait for a message form one of the int_doubler or the Plus processes
    receive
        N ->
            case Answers of
                [X, Y] -> % if we have already 2 then this is the last
                    Result = io_lib:format("~w + ~w + ~w = ~w~n", [X, Y, N, X + Y + N]),
                    Main ! lists:flatten(Result);
                _ -> collector(Answers ++ [N], Main)
            end
    end.

start() ->
    % spawn one process to collect the data
    Collector = spawn(?MODULE, collector, [[], self()]),

    % spawn 3 processes to process data in background
    spawn(?MODULE, int_doubler, [10, Collector]),
    spawn(?MODULE, int_doubler, [20, Collector]),
    Plus = fun (A, B) -> Collector ! A + B end,
    spawn(fun() -> Plus(10, 22) end),

    % wait for a message from the collector process and print it
    receive
        Result -> io:format("~s", [Result])
    end.

I don't have the distinction between chanels and threads/goroutines, everything is just a process and every process can send messages to other processes. In the end I assume one would do stuff like that in a general way with OTP's gen_fsm or something similar.

@elimisteve

This comment has been minimized.

Show comment Hide comment
@elimisteve

elimisteve Jan 3, 2013

Executable Go version here: http://play.golang.org/p/YRSMAvjd5B

Owner

elimisteve commented Jan 3, 2013

Executable Go version here: http://play.golang.org/p/YRSMAvjd5B

@anarazel

This comment has been minimized.

Show comment Hide comment
@anarazel

anarazel Jan 3, 2013

More than slightly annoyed that authentication is required for gists these days... Anyway, here's the absolutely inelegant but short C variant of this.

/* gcc -std=c99 -fopenmp -Wall test.c -o test -lrt && ./test */
#include

int main(int argc, char *argv[]) {
int data[] = {10, 20, 30};
const int loops = sizeof(data)/sizeof(int);

#pragma omp parallel for schedule(dynamic, 1)
for (int i = 0; i < loops; i++)
{
if (i == loops - 1)
data[i] += 40;
else
data[i] *= 2;
}

printf("data: %i %i %i = %i\n", data[0], data[1], data[2],
       data[0] + data[1] + data[2]);
return 0;

}

anarazel commented Jan 3, 2013

More than slightly annoyed that authentication is required for gists these days... Anyway, here's the absolutely inelegant but short C variant of this.

/* gcc -std=c99 -fopenmp -Wall test.c -o test -lrt && ./test */
#include

int main(int argc, char *argv[]) {
int data[] = {10, 20, 30};
const int loops = sizeof(data)/sizeof(int);

#pragma omp parallel for schedule(dynamic, 1)
for (int i = 0; i < loops; i++)
{
if (i == loops - 1)
data[i] += 40;
else
data[i] *= 2;
}

printf("data: %i %i %i = %i\n", data[0], data[1], data[2],
       data[0] + data[1] + data[2]);
return 0;

}
@jonte

This comment has been minimized.

Show comment Hide comment
@jonte

jonte Jan 3, 2013

Some haskell, perhaps? :)

import Control.Concurrent

intDoubler :: MVar Int -> Int -> IO ()
intDoubler v n = putMVar v (n*2)

intSum :: MVar Int -> MVar Int -> MVar Int -> MVar Int -> IO ()
intSum v1 v2 v3 s = do
  i1 <- takeMVar v1
  i2 <- takeMVar v2
  i3 <- takeMVar v3
  putMVar s (i1 + i2 + i3)

main :: IO ()
main = do
  v1 <- newEmptyMVar
  v2 <- newEmptyMVar
  v3 <- newEmptyMVar
  vs <- newEmptyMVar
  forkIO $ intDoubler v1 10
  forkIO $ intDoubler v2 20
  forkIO $ (\v3 i1 i2 -> putMVar v3 (i1 + i2)) v3 30 40
  forkIO $ intSum v1 v2 v3 vs
  result <- takeMVar vs
  print result

-- *Main> main 
-- 130

jonte commented Jan 3, 2013

Some haskell, perhaps? :)

import Control.Concurrent

intDoubler :: MVar Int -> Int -> IO ()
intDoubler v n = putMVar v (n*2)

intSum :: MVar Int -> MVar Int -> MVar Int -> MVar Int -> IO ()
intSum v1 v2 v3 s = do
  i1 <- takeMVar v1
  i2 <- takeMVar v2
  i3 <- takeMVar v3
  putMVar s (i1 + i2 + i3)

main :: IO ()
main = do
  v1 <- newEmptyMVar
  v2 <- newEmptyMVar
  v3 <- newEmptyMVar
  vs <- newEmptyMVar
  forkIO $ intDoubler v1 10
  forkIO $ intDoubler v2 20
  forkIO $ (\v3 i1 i2 -> putMVar v3 (i1 + i2)) v3 30 40
  forkIO $ intSum v1 v2 v3 vs
  result <- takeMVar vs
  print result

-- *Main> main 
-- 130
@elimisteve

This comment has been minimized.

Show comment Hide comment
@elimisteve

elimisteve Jan 3, 2013

@anarazel I didn't know there were C libraries that auto-spawned threads... that's pretty awesome.

@jonte And yes, hard to say no to Haskell :-)

Thanks for the code samples, all! I'd still like to see some Scala and Clojure up in here...

Owner

elimisteve commented Jan 3, 2013

@anarazel I didn't know there were C libraries that auto-spawned threads... that's pretty awesome.

@jonte And yes, hard to say no to Haskell :-)

Thanks for the code samples, all! I'd still like to see some Scala and Clojure up in here...

@danielsz

This comment has been minimized.

Show comment Hide comment
@danielsz

danielsz Jan 5, 2013

My take with Clojure and the future construct.

  (let [x (future (* 2 10))
        y (future (* 2 20))
        z (future (+ 30 40))
        result (future (str @x " + " @y " + " @z " = " (+ @x @y @z)))]
    (println @result))

danielsz commented Jan 5, 2013

My take with Clojure and the future construct.

  (let [x (future (* 2 10))
        y (future (* 2 20))
        z (future (+ 30 40))
        result (future (str @x " + " @y " + " @z " = " (+ @x @y @z)))]
    (println @result))
@elimisteve

This comment has been minimized.

Show comment Hide comment
@elimisteve

elimisteve Jan 5, 2013

@danielsz Very elegant! Do futures automatically run concurrently in Clojure? And what about in parallel; are you using multiple cores (even though that wouldn't speed things up with the specific values we're using here)?

Owner

elimisteve commented Jan 5, 2013

@danielsz Very elegant! Do futures automatically run concurrently in Clojure? And what about in parallel; are you using multiple cores (even though that wouldn't speed things up with the specific values we're using here)?

@danielsz

This comment has been minimized.

Show comment Hide comment
@danielsz

danielsz Jan 5, 2013

Hi Steve,

From the docs: A future takes a body of expressions and yields a future object that will invoke the body in another thread, and will cache the result and return it on all subsequent calls to deref/@.

Clojure runs on the JVM, where threads are native. I don't know if the JVM always distributes threads across multiple cores. A JVM expert should be able to shed some light.

Clojure has rich concurrency semantics, and I'm pretty sure there are other ways to achieve the same effect. I used futures because it seemed to me the appropriate construct for this exercise.

danielsz commented Jan 5, 2013

Hi Steve,

From the docs: A future takes a body of expressions and yields a future object that will invoke the body in another thread, and will cache the result and return it on all subsequent calls to deref/@.

Clojure runs on the JVM, where threads are native. I don't know if the JVM always distributes threads across multiple cores. A JVM expert should be able to shed some light.

Clojure has rich concurrency semantics, and I'm pretty sure there are other ways to achieve the same effect. I used futures because it seemed to me the appropriate construct for this exercise.

@danielsz

This comment has been minimized.

Show comment Hide comment
@danielsz

danielsz Jan 5, 2013

Just for the record, for those that prefer the printf idiom, you can do it like so when binding to result:

(future (format "%1$d + %2$d + %3$d = %4$d" @x @y @z (+ @x @y @z)))

danielsz commented Jan 5, 2013

Just for the record, for those that prefer the printf idiom, you can do it like so when binding to result:

(future (format "%1$d + %2$d + %3$d = %4$d" @x @y @z (+ @x @y @z)))
@graue

This comment has been minimized.

Show comment Hide comment
@graue

graue Jan 5, 2013

Finally figured this out in Rust! Note: I'm a total Rust n00b, so it's extremely likely that this could be made more elegant. The repetition of chan.clone() is especially upsetting to my eyes, but it does the job:

extern mod std;
use task::spawn;
use pipes::{stream, Port, Chan, SharedChan};

// Purely functional doubler
// No need to combine computation / means of sending it in the same function
// In a real example, this could be an expensive computation
fn double(x: int) -> int {
    x * 2
}

fn main() {
    // Create port/channel pair for receiving/sending ints, respectively
    let (port, chan): (Port<int>, Chan<int>) = stream();
    // To allow multiple tasks to write, turn the channel into a SharedChan
    let chan = SharedChan(move chan);

    // Spawn 3 tasks to process data in the background,
    // each writing to its own clone of the SharedChan
    let child = chan.clone();
    do spawn |move child| { child.send(double(10)); }
    let child = chan.clone();
    do spawn |move child| { child.send(double(20)); }
    let child = chan.clone();
    do spawn |move child| { child.send((|a: int, b: int| a+b)(30, 40)); }

    // Make port/channel pair for the string result
    let (result_port, result_chan): (Port<~str>, Chan<~str>) = stream();
    do spawn |move port, move result_chan| {
        let (x, y, z) = (port.recv(), port.recv(), port.recv());
        let result: ~str = fmt!("%d + %d + %d = %d", x, y, z, x+y+z);
        result_chan.send(move result);
    }

    // Receive and print result
    io::println(result_port.recv());
}

graue commented Jan 5, 2013

Finally figured this out in Rust! Note: I'm a total Rust n00b, so it's extremely likely that this could be made more elegant. The repetition of chan.clone() is especially upsetting to my eyes, but it does the job:

extern mod std;
use task::spawn;
use pipes::{stream, Port, Chan, SharedChan};

// Purely functional doubler
// No need to combine computation / means of sending it in the same function
// In a real example, this could be an expensive computation
fn double(x: int) -> int {
    x * 2
}

fn main() {
    // Create port/channel pair for receiving/sending ints, respectively
    let (port, chan): (Port<int>, Chan<int>) = stream();
    // To allow multiple tasks to write, turn the channel into a SharedChan
    let chan = SharedChan(move chan);

    // Spawn 3 tasks to process data in the background,
    // each writing to its own clone of the SharedChan
    let child = chan.clone();
    do spawn |move child| { child.send(double(10)); }
    let child = chan.clone();
    do spawn |move child| { child.send(double(20)); }
    let child = chan.clone();
    do spawn |move child| { child.send((|a: int, b: int| a+b)(30, 40)); }

    // Make port/channel pair for the string result
    let (result_port, result_chan): (Port<~str>, Chan<~str>) = stream();
    do spawn |move port, move result_chan| {
        let (x, y, z) = (port.recv(), port.recv(), port.recv());
        let result: ~str = fmt!("%d + %d + %d = %d", x, y, z, x+y+z);
        result_chan.send(move result);
    }

    // Receive and print result
    io::println(result_port.recv());
}
@ocharles

This comment has been minimized.

Show comment Hide comment
@ocharles

ocharles Jan 5, 2013

Another Haskell solution, this one uses sparks and Control.Parallel

import Control.Parallel

main :: IO ()
main = putStrLn . show $ a `par` b `par` c `par` result `par` result
  where double = (2 *)
        a = double 10
        b = double 20
        c = 30 + 40
        result = a + b + c

And running it:

./parallel +RTS -N2 -sstderr
130
          55,188 bytes allocated in the heap
              20 bytes copied during GC
          45,692 bytes maximum residency (1 sample(s))
          23,940 bytes maximum slop
               2 MB total memory in use (0 MB lost due to fragmentation)

                                    Tot time (elapsed)  Avg pause  Max pause
  Gen  0         0 colls,     0 par    0.00s    0.00s     0.0000s    0.0000s
  Gen  1         1 colls,     0 par    0.00s    0.00s     0.0001s    0.0001s

  Parallel GC work balance: -nan% (serial 0%, perfect 100%)

  TASKS: 4 (1 bound, 3 peak workers (3 total), using -N2)

  SPARKS: 4 (0 converted, 0 overflowed, 0 dud, 0 GC'd, 4 fizzled)

  INIT    time    0.00s  (  0.00s elapsed)
  MUT     time    0.00s  (  0.00s elapsed)
  GC      time    0.00s  (  0.00s elapsed)
  EXIT    time    0.00s  (  0.00s elapsed)
  Total   time    0.00s  (  0.00s elapsed)

  Alloc rate    596,150,106 bytes per MUT second

  Productivity  87.6% of total user, 211.7% of total elapsed

ocharles commented Jan 5, 2013

Another Haskell solution, this one uses sparks and Control.Parallel

import Control.Parallel

main :: IO ()
main = putStrLn . show $ a `par` b `par` c `par` result `par` result
  where double = (2 *)
        a = double 10
        b = double 20
        c = 30 + 40
        result = a + b + c

And running it:

./parallel +RTS -N2 -sstderr
130
          55,188 bytes allocated in the heap
              20 bytes copied during GC
          45,692 bytes maximum residency (1 sample(s))
          23,940 bytes maximum slop
               2 MB total memory in use (0 MB lost due to fragmentation)

                                    Tot time (elapsed)  Avg pause  Max pause
  Gen  0         0 colls,     0 par    0.00s    0.00s     0.0000s    0.0000s
  Gen  1         1 colls,     0 par    0.00s    0.00s     0.0001s    0.0001s

  Parallel GC work balance: -nan% (serial 0%, perfect 100%)

  TASKS: 4 (1 bound, 3 peak workers (3 total), using -N2)

  SPARKS: 4 (0 converted, 0 overflowed, 0 dud, 0 GC'd, 4 fizzled)

  INIT    time    0.00s  (  0.00s elapsed)
  MUT     time    0.00s  (  0.00s elapsed)
  GC      time    0.00s  (  0.00s elapsed)
  EXIT    time    0.00s  (  0.00s elapsed)
  Total   time    0.00s  (  0.00s elapsed)

  Alloc rate    596,150,106 bytes per MUT second

  Productivity  87.6% of total user, 211.7% of total elapsed
@graue

This comment has been minimized.

Show comment Hide comment
@graue

graue Jan 5, 2013

Hmm, the Haskell versions don't seem to output what they're supposed to, which is the string

20 + 40 + 70 = 130

with a newline. @elimisteve's Go, @jeena's Erlang, @danielsz's Clojure and my Rust all print it like this and @anarazel's C is close but also prints "data: " in front. However, @jonte and @ocharles, your Haskell versions seem to only print 130.

graue commented Jan 5, 2013

Hmm, the Haskell versions don't seem to output what they're supposed to, which is the string

20 + 40 + 70 = 130

with a newline. @elimisteve's Go, @jeena's Erlang, @danielsz's Clojure and my Rust all print it like this and @anarazel's C is close but also prints "data: " in front. However, @jonte and @ocharles, your Haskell versions seem to only print 130.

@esd

This comment has been minimized.

Show comment Hide comment
@esd

esd Jan 6, 2013

I don't mean to bash @jeena's nice Erlang code, but here is my quick take on it:

-module (foo).
-compile (export_all).

collect_3(Target, [X, Y, Z] = L) ->
    Target ! io_lib:format("~w + ~w + ~w = ~w~n", [Z, Y, X, lists:sum(L)]);
collect_3(Target, L) ->
    receive V -> collect_3(Target, [V | L]) end.

main() ->
    Collector = spawn(?MODULE, collect_3, [self(), []]),
    spawn(fun() -> Collector ! 10 * 2 end),
    spawn(fun() -> Collector ! 20 * 2 end),
    spawn(fun() -> Collector ! 30 + 40 end),
    receive X -> io:format(X) end.

Example:

$ erl
1> c(foo).
{ok,foo}
2> foo:main().
20 + 40 + 70 = 130
ok
3>

esd commented Jan 6, 2013

I don't mean to bash @jeena's nice Erlang code, but here is my quick take on it:

-module (foo).
-compile (export_all).

collect_3(Target, [X, Y, Z] = L) ->
    Target ! io_lib:format("~w + ~w + ~w = ~w~n", [Z, Y, X, lists:sum(L)]);
collect_3(Target, L) ->
    receive V -> collect_3(Target, [V | L]) end.

main() ->
    Collector = spawn(?MODULE, collect_3, [self(), []]),
    spawn(fun() -> Collector ! 10 * 2 end),
    spawn(fun() -> Collector ! 20 * 2 end),
    spawn(fun() -> Collector ! 30 + 40 end),
    receive X -> io:format(X) end.

Example:

$ erl
1> c(foo).
{ok,foo}
2> foo:main().
20 + 40 + 70 = 130
ok
3>
@yoavrubin

This comment has been minimized.

Show comment Hide comment
@yoavrubin

yoavrubin Jan 6, 2013

Here's another one with Clojure

(let [v (pmap #(eval %) '[(* 2 10)(* 2 20)(+ 30 40)])]
(println @(future (str (reduce #(str %1 "+" %2) v) "=" (reduce + v)))))

Here's another one with Clojure

(let [v (pmap #(eval %) '[(* 2 10)(* 2 20)(+ 30 40)])]
(println @(future (str (reduce #(str %1 "+" %2) v) "=" (reduce + v)))))
@nizox

This comment has been minimized.

Show comment Hide comment
@nizox

nizox Jan 6, 2013

One line with bash!

(expr 10 \* 2 & expr 20 \* 2 & expr 30 \+ 40) | (read a; read b; read c; echo "\"$a + $b + $c = \"; $a + $b + $c" | bc)

nizox commented Jan 6, 2013

One line with bash!

(expr 10 \* 2 & expr 20 \* 2 & expr 30 \+ 40) | (read a; read b; read c; echo "\"$a + $b + $c = \"; $a + $b + $c" | bc)
@mnicky

This comment has been minimized.

Show comment Hide comment
@mnicky

mnicky Jan 7, 2013

@yoavrubin: the first line of your Clojure example can be made even more succint and clear:

(let [v (pvalues (* 2 10) (* 2 20) (+ 30 40))]

And using a function instead of let, it can also be made an one-liner:

(println @(future (#(str (apply str (interpose \+ %)) \= (apply + %)) (pvalues (* 2 10) (* 2 20) (+ 30 40)))))

When squeezed as much as possible (and loosing a clarity), it also fits into the one line of a gist comment:

(print@(future(#(str(apply str(interpose\+%))\=(apply +%))(pvalues(* 2 10)(* 2 20)(+ 30 40)))))

mnicky commented Jan 7, 2013

@yoavrubin: the first line of your Clojure example can be made even more succint and clear:

(let [v (pvalues (* 2 10) (* 2 20) (+ 30 40))]

And using a function instead of let, it can also be made an one-liner:

(println @(future (#(str (apply str (interpose \+ %)) \= (apply + %)) (pvalues (* 2 10) (* 2 20) (+ 30 40)))))

When squeezed as much as possible (and loosing a clarity), it also fits into the one line of a gist comment:

(print@(future(#(str(apply str(interpose\+%))\=(apply +%))(pvalues(* 2 10)(* 2 20)(+ 30 40)))))
@aeonshifter

This comment has been minimized.

Show comment Hide comment
@aeonshifter

aeonshifter Jan 7, 2013

using System;
using System.Linq;
using System.Threading.Tasks;

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine(
            Task.WhenAll(
                Task.Run(() => 10 * 2), Task.Run(() => 20 * 2), Task.Run(() => 30 + 40))
            .ContinueWith(t => string.Join(" + ", t.Result) + " = " + t.Result.Sum()).Result
        );
    }
}
using System;
using System.Linq;
using System.Threading.Tasks;

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine(
            Task.WhenAll(
                Task.Run(() => 10 * 2), Task.Run(() => 20 * 2), Task.Run(() => 30 + 40))
            .ContinueWith(t => string.Join(" + ", t.Result) + " = " + t.Result.Sum()).Result
        );
    }
}
@elimisteve

This comment has been minimized.

Show comment Hide comment
@elimisteve

elimisteve Jan 7, 2013

Awesome guys, these are great.

@nizox Other than using ampersands to background processes, I didn't know it was so easy to do asynchronous programming at the command line. Sweet.

@aeonshifter I can see why using C# is much nicer than Java.

Looks like I'm gonna have to step up my game and make my Go example more succinct...

Owner

elimisteve commented Jan 7, 2013

Awesome guys, these are great.

@nizox Other than using ampersands to background processes, I didn't know it was so easy to do asynchronous programming at the command line. Sweet.

@aeonshifter I can see why using C# is much nicer than Java.

Looks like I'm gonna have to step up my game and make my Go example more succinct...

@elimisteve

This comment has been minimized.

Show comment Hide comment
@elimisteve

elimisteve Jan 7, 2013

package main

import "fmt"

func main() {
    ch := make(chan int)
    answer := make(chan string)

    intDoubler := func(n int) { ch <- n*2 }
    go intDoubler(10)
    go intDoubler(20)
    go func(a, b int) { ch <- a+b }(30, 40)

    go func() {
        x, y, z := <-ch, <-ch, <-ch
        answer <- fmt.Sprintf("%d + %d + %d = %d", x, y, z, x+y+z)
    }()

    fmt.Printf("%s\n", <-answer)
}
Owner

elimisteve commented Jan 7, 2013

package main

import "fmt"

func main() {
    ch := make(chan int)
    answer := make(chan string)

    intDoubler := func(n int) { ch <- n*2 }
    go intDoubler(10)
    go intDoubler(20)
    go func(a, b int) { ch <- a+b }(30, 40)

    go func() {
        x, y, z := <-ch, <-ch, <-ch
        answer <- fmt.Sprintf("%d + %d + %d = %d", x, y, z, x+y+z)
    }()

    fmt.Printf("%s\n", <-answer)
}
@elimisteve

This comment has been minimized.

Show comment Hide comment
@elimisteve

elimisteve Jan 7, 2013

Bending the rules a bit, similar to other examples...

package main

func main() {
    ch := make(chan int)

    go func(a int)    { ch <- a*2 }(10)
    go func(a int)    { ch <- a*2 }(20)
    go func(a, b int) { ch <- a+b }(30, 40)

    x, y, z := <-ch, <-ch, <-ch
    println(x, "+", y, "+", z, "=", x+y+z)
}
Owner

elimisteve commented Jan 7, 2013

Bending the rules a bit, similar to other examples...

package main

func main() {
    ch := make(chan int)

    go func(a int)    { ch <- a*2 }(10)
    go func(a int)    { ch <- a*2 }(20)
    go func(a, b int) { ch <- a+b }(30, 40)

    x, y, z := <-ch, <-ch, <-ch
    println(x, "+", y, "+", z, "=", x+y+z)
}
@gholms

This comment has been minimized.

Show comment Hide comment
@gholms

gholms Jan 8, 2013

I'm noticing a distinct lack of python here. :P

from concurrent.futures import Future, ThreadPoolExecutor

def fmt_sum(*int_futures):
    ints = tuple(map(Future.result, int_futures))
    return ' + '.join(map(str, ints)) + ' = ' + str(sum(ints))

with ThreadPoolExecutor(max_workers=4) as tp:
    a = tp.submit(lambda x: x * 2, 10)
    b = tp.submit(lambda x: x * 2, 20)
    c = tp.submit(lambda x, y: x + y, 30, 40)
    d = tp.submit(fmt_sum, a, b, c)

print(d.result())

gholms commented Jan 8, 2013

I'm noticing a distinct lack of python here. :P

from concurrent.futures import Future, ThreadPoolExecutor

def fmt_sum(*int_futures):
    ints = tuple(map(Future.result, int_futures))
    return ' + '.join(map(str, ints)) + ' = ' + str(sum(ints))

with ThreadPoolExecutor(max_workers=4) as tp:
    a = tp.submit(lambda x: x * 2, 10)
    b = tp.submit(lambda x: x * 2, 20)
    c = tp.submit(lambda x, y: x + y, 30, 40)
    d = tp.submit(fmt_sum, a, b, c)

print(d.result())
@bstrie

This comment has been minimized.

Show comment Hide comment
@bstrie

bstrie Jan 8, 2013

Here's an update of the Rust solution:

use task::spawn;

fn main() {
    let (port, chan) = pipes::stream();
    let chan = pipes::SharedChan(chan);

    let (s1, s2, s3) = (chan.clone(), chan.clone(), chan.clone());
    do spawn { s1.send( (|a: int| a*2)(10) ) }
    do spawn { s2.send( (|a: int| a*2)(20) ) }
    do spawn { s3.send( (|a: int, b: int| a+b)(30, 40) ) }

    let (x, y, z) = (port.recv(), port.recv(), port.recv());
    io::println(fmt!("%d + %d + %d = %d", x, y, z, x+y+z));
}

bstrie commented Jan 8, 2013

Here's an update of the Rust solution:

use task::spawn;

fn main() {
    let (port, chan) = pipes::stream();
    let chan = pipes::SharedChan(chan);

    let (s1, s2, s3) = (chan.clone(), chan.clone(), chan.clone());
    do spawn { s1.send( (|a: int| a*2)(10) ) }
    do spawn { s2.send( (|a: int| a*2)(20) ) }
    do spawn { s3.send( (|a: int, b: int| a+b)(30, 40) ) }

    let (x, y, z) = (port.recv(), port.recv(), port.recv());
    io::println(fmt!("%d + %d + %d = %d", x, y, z, x+y+z));
}
@bstrie

This comment has been minimized.

Show comment Hide comment
@bstrie

bstrie Jan 8, 2013

Oh hey, turns out Rust has a futures library after all:

extern mod std;
use std::future::spawn;

fn main() {
    let p1 = do spawn { (|a: int| a*2)(10) },
        p2 = do spawn { (|a: int| a*2)(20) },
        p3 = do spawn { (|a: int, b: int| a+b)(30, 40) };

    let (x, y, z) = (p1.get(), p2.get(), p3.get());
    io::println(fmt!("%d + %d + %d = %d", x, y, z, x+y+z));
}

bstrie commented Jan 8, 2013

Oh hey, turns out Rust has a futures library after all:

extern mod std;
use std::future::spawn;

fn main() {
    let p1 = do spawn { (|a: int| a*2)(10) },
        p2 = do spawn { (|a: int| a*2)(20) },
        p3 = do spawn { (|a: int, b: int| a+b)(30, 40) };

    let (x, y, z) = (p1.get(), p2.get(), p3.get());
    io::println(fmt!("%d + %d + %d = %d", x, y, z, x+y+z));
}
@rntz

This comment has been minimized.

Show comment Hide comment
@rntz

rntz Jan 8, 2013

A shorter (but still readable) Haskell solution using ForkIO. Also, formatted as requested.

import Control.Concurrent
import Data.List (intercalate)

main = do
  ch <- newChan
  answer <- newEmptyMVar
  mapM (\e -> forkIO $ seq e $ writeChan ch e)
       [10 * 2, 20 * 2, 30 + 40]
  forkIO $ do nums <- mapM readChan [ch,ch,ch]
              let ans = intercalate " + " (map show nums)
                        ++ " = " ++ show (sum nums)
              seq ans $ putMVar answer ans
  putStrLn =<< takeMVar answer

Haskell's laziness has to be carefully considered to ensure that the multiplications & additions run on the right thread. forkIO isn't really designed for scheduling pure computations onto multiple threads; par is probably a better choice here. I checked the above using Debug.Trace and myThreadId, and it seems to do the right thing.

rntz commented Jan 8, 2013

A shorter (but still readable) Haskell solution using ForkIO. Also, formatted as requested.

import Control.Concurrent
import Data.List (intercalate)

main = do
  ch <- newChan
  answer <- newEmptyMVar
  mapM (\e -> forkIO $ seq e $ writeChan ch e)
       [10 * 2, 20 * 2, 30 + 40]
  forkIO $ do nums <- mapM readChan [ch,ch,ch]
              let ans = intercalate " + " (map show nums)
                        ++ " = " ++ show (sum nums)
              seq ans $ putMVar answer ans
  putStrLn =<< takeMVar answer

Haskell's laziness has to be carefully considered to ensure that the multiplications & additions run on the right thread. forkIO isn't really designed for scheduling pure computations onto multiple threads; par is probably a better choice here. I checked the above using Debug.Trace and myThreadId, and it seems to do the right thing.

@charl

This comment has been minimized.

Show comment Hide comment
@charl

charl Jan 9, 2013

Ruby (works in MRI, RBX and Jruby):

require "rubygems"
require "celluloid"

ws = []
times_two = lambda { |x| x * 2 }
ws << Celluloid::Future.new { times_two.call(10) }
ws << Celluloid::Future.new { times_two.call(20) }
ws << Celluloid::Future.new { lambda { |x,y| x + y }.call(30, 40) }
r = Celluloid::Future.new do
  vs = ws.map { |w| w.value }
  "#{vs.join(" + ")} = #{vs.reduce(:+)}"
end

puts r.value

charl commented Jan 9, 2013

Ruby (works in MRI, RBX and Jruby):

require "rubygems"
require "celluloid"

ws = []
times_two = lambda { |x| x * 2 }
ws << Celluloid::Future.new { times_two.call(10) }
ws << Celluloid::Future.new { times_two.call(20) }
ws << Celluloid::Future.new { lambda { |x,y| x + y }.call(30, 40) }
r = Celluloid::Future.new do
  vs = ws.map { |w| w.value }
  "#{vs.join(" + ")} = #{vs.reduce(:+)}"
end

puts r.value
@tzach

This comment has been minimized.

Show comment Hide comment
@tzach

tzach Jan 9, 2013

Slight variation on Yoav (excellent) Clojure solution, replacing the eval with pcalls to functions.

(let [v (pcalls #(* 2 10) #(* 2 20) #(+ 30 40))] 
   (println @(future (str (reduce #(str %1 "+" %2) v) "=" (reduce + v)))))

Just notice @mnicky had even better solution with pvalues...

tzach commented Jan 9, 2013

Slight variation on Yoav (excellent) Clojure solution, replacing the eval with pcalls to functions.

(let [v (pcalls #(* 2 10) #(* 2 20) #(+ 30 40))] 
   (println @(future (str (reduce #(str %1 "+" %2) v) "=" (reduce + v)))))

Just notice @mnicky had even better solution with pvalues...

@spider-mario

This comment has been minimized.

Show comment Hide comment
@spider-mario

spider-mario Jan 10, 2013

Mozart/Oz:

functor
import
    Application System
define X Y Z S in
    thread X =  2 * 10 end
    thread Y =  2 * 20 end
    thread Z = 30 + 40 end

    thread S = X#" + "#Y#" + "#Z#" = "#(X + Y + Z) end

    {System.showInfo S}
    {Application.exit 0}
end

Mozart/Oz:

functor
import
    Application System
define X Y Z S in
    thread X =  2 * 10 end
    thread Y =  2 * 20 end
    thread Z = 30 + 40 end

    thread S = X#" + "#Y#" + "#Z#" = "#(X + Y + Z) end

    {System.showInfo S}
    {Application.exit 0}
end
@mikera

This comment has been minimized.

Show comment Hide comment
@mikera

mikera Jan 16, 2013

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))))

mikera commented Jan 16, 2013

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))))
@velvia

This comment has been minimized.

Show comment Hide comment
@velvia

velvia Jan 24, 2013

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.

velvia commented Jan 24, 2013

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.

@velvia

This comment has been minimized.

Show comment Hide comment
@velvia

velvia Jan 24, 2013

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

velvia commented Jan 24, 2013

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

@vsrinivas

This comment has been minimized.

Show comment Hide comment
@vsrinivas

vsrinivas Apr 2, 2013

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;
}

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;
}
@coreyoconnor

This comment has been minimized.

Show comment Hide comment
@coreyoconnor

coreyoconnor Aug 16, 2013

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

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
@robinp

This comment has been minimized.

Show comment Hide comment
@robinp

robinp Nov 16, 2013

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)

robinp commented Nov 16, 2013

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)
@geraldstanje

This comment has been minimized.

Show comment Hide comment
@geraldstanje

geraldstanje Aug 24, 2014

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)

}

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)

}

@polonskiy

This comment has been minimized.

Show comment Hide comment
@polonskiy

polonskiy Dec 4, 2014

@timhuff

This comment has been minimized.

Show comment Hide comment
@timhuff

timhuff Sep 28, 2015

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);
}

timhuff commented Sep 28, 2015

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);
}
@Zizaco

This comment has been minimized.

Show comment Hide comment
@Zizaco

Zizaco Jan 12, 2016

@polonskiy Actually, I'm not even mad! That's amazing 😨

Zizaco commented Jan 12, 2016

@polonskiy Actually, I'm not even mad! That's amazing 😨

@elimisteve

This comment has been minimized.

Show comment Hide comment
@elimisteve

elimisteve Mar 12, 2017

Would be interesting to see this done with http://libmill.org/ !

Owner

elimisteve commented Mar 12, 2017

Would be interesting to see this done with http://libmill.org/ !

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment