38
\$\begingroup\$

I have a challenge for you:

  • Print "Hello World" using any language.
  • Each character must be printed from its own, unique thread

That's it. Obviously, as there's no guarantee that the threads will operate in the order you start them, you have to make your program thread safe to ensure the output is printed in the right order.

And, because this is code golf, the shortest program wins.

Update:

The winner is Marinus' APL entry, at 34 characters. It also wins the prize for the least readable entry.

\$\endgroup\$
7
  • 10
    \$\begingroup\$ A better name for this would have been HelolW rdlo \$\endgroup\$ May 19, 2012 at 16:36
  • \$\begingroup\$ Ha, I like that. Changing it right away :D \$\endgroup\$
    – Tharwen
    May 19, 2012 at 17:02
  • \$\begingroup\$ Aww... it's too short \$\endgroup\$
    – Tharwen
    May 19, 2012 at 17:02
  • 1
    \$\begingroup\$ It is funny to see how many people ignore the "obviously, as there's no guarantee that the threads will operate in the order you start them" hint and think they got it right. \$\endgroup\$
    – Joa Ebert
    May 20, 2012 at 8:47
  • \$\begingroup\$ Albeit it's true that "there's no guarantee that the threads will operate in the order you start them" in practice they will almost always do for such a trivial program. To avoid this confusion I'd add to the problem that each thread must 1) wait a (small) random number of milliseconds 2) output its char 3) wait for another random (maybe long) amount of time This way people could tell if the code works by just running it a couple of times. And the join() solutions would perform much worse. Without random waiting one could be mislead by a successful run to think that his program is correct. \$\endgroup\$
    – silviot
    May 21, 2012 at 11:52

25 Answers 25

19
\$\begingroup\$

C, 61 62 chars

i;main(){write(1,"Hello World\n"+i++,1);i>13||fork()||main();}

The pthread library functions all have loooooong names, so instead I fired up an entire separate process for each character. fork() is so much shorter.

It was necessary to use write() instead of putchar() because the stdio buffering functions are not thread-safe.

Edited: Back up to 62 chars. In my zeal, dropping down to 61 chars also dropped the thread-safety.

\$\endgroup\$
8
  • \$\begingroup\$ It should be possible to changed the write statement to write(1,"Hello World\n",!!++i) for 2 bytes. Nice solution otherwise. \$\endgroup\$
    – primo
    May 19, 2012 at 17:30
  • \$\begingroup\$ You should try that and see what it produces. \$\endgroup\$
    – breadbox
    May 19, 2012 at 17:32
  • \$\begingroup\$ My mistake, I meant !!++i \$\endgroup\$
    – primo
    May 19, 2012 at 17:34
  • \$\begingroup\$ That appears to be what you wrote the first time, so I don't see what mistake you were trying to correct. And I wasn't being facetious: I honestly meant that you should try it yourself and see what happens. By removing the addition, every thread will just print the first character of the string. \$\endgroup\$
    – breadbox
    May 19, 2012 at 17:44
  • \$\begingroup\$ I had originally written !!i++, but edited it a few seconds later, because I realized it would evaluate to 0 on the first iteration. I assumed you had seen the unedited version. I'm not able to test your code, because it only prints out the very first character, once. There's a lot of alternatives though; i++<13, using !!i, or even write(1,"Hello World\n",i++>13||fork()||main()) \$\endgroup\$
    – primo
    May 19, 2012 at 17:55
10
\$\begingroup\$

APL (Dyalog) (44 43 39 34)

{⍞←⍺⊣⎕DL⍵}&⌿2 11⍴'Hello World',⍳11

Explanation:

  • 2 11⍴'Hello World',⍳11 creates a matrix: (H,1), (e,2), ...
  • &⌿ means: for each column of the matrix, do on a separate thread:
  • In a thread, is now the character and is now the time
  • ⎕DL⊃⍵ waits for seconds.
  • Then, ⍞←⍺ outputs the character.
\$\endgroup\$
2
  • 11
    \$\begingroup\$ You know what? I'll take your word for it... :) \$\endgroup\$
    – Bolster
    May 20, 2012 at 9:02
  • \$\begingroup\$ OK, this is the shortest. Congratulations! \$\endgroup\$
    – Tharwen
    May 25, 2012 at 8:11
9
\$\begingroup\$

Ruby, 46 characters

"Hello World".chars{|c|Thread.new{$><<c}.join}

It is synchronized due to the fact that the program waits for the thread to end before starting the next thread and continuing with the next char.

\$\endgroup\$
7
\$\begingroup\$

Pythonect (35 chars)

http://www.pythonect.org

"Hello World"|list|_.split()->print
\$\endgroup\$
5
  • \$\begingroup\$ This is the shortest so far. Since I have no idea what it actually does, I'll assume it's correct and accept it in a day or two if no-one speaks out against it or posts anything shorter. \$\endgroup\$
    – Tharwen
    May 22, 2012 at 19:59
  • 1
    \$\begingroup\$ Just had a brief look at the examples. Shouldn't print statement or list statement have brackets [] around it? \$\endgroup\$
    – user3538
    May 22, 2012 at 22:19
  • 1
    \$\begingroup\$ Hi, im forwarding Itzik's(creator of pythonect) answer: '->' and '|' are both Pythonect operators. The pipe operator passes one item at a item, while the other operator passes all items at once. What the program above does is, it takes "Hello World" string, turn's it into a list, split the list to chars, and send each char to print. It's possible to optimize the program even further, to the following: iter("Hello World") | print What it does is, it iterates "Hello World" string, and send each char to print (in a sync/blocking manner). Regards, Itzik Kotler | ikotler.org \$\endgroup\$ May 22, 2012 at 22:36
  • \$\begingroup\$ how is the threading being done here??? \$\endgroup\$
    – Rohit
    May 24, 2012 at 10:55
  • 1
    \$\begingroup\$ Like @LeonFedotov mentioned, and from the pythonect source (available at pythonect) after parsing, for each iteration and the '->' operator, threading is done like this: thread = threading.Thread(target=__run, args=([(operator, item)] + expression[1:], copy.copy(globals_), copy.copy(locals_), return_value_queue, not iterate_literal_arrays)) thread.start() \$\endgroup\$ May 24, 2012 at 11:44
6
\$\begingroup\$

Python (101 93 98)

This is Peter Taylor's solution. It works by delaying printing the N-th character by N seconds. See comments.

import sys.threading as t
for x in range(11):t.Timer(x,sys.stdout.write,"Hello World"[x]).start()

This is the original one:

import sys,threading as t
for x in "Hello World":t.Thread(None,sys.stdout.write,x,x).start()

It worked because the time it takes to print a single character is less than the time it takes Python to initialize a new thread, therefore the N-th thread would finish before the N+1-th thread was created. Apparently it is against the rules to rely on this.

\$\endgroup\$
6
  • \$\begingroup\$ You can save 3 chars by changing import sys,threading to import sys,threading as t and you can save 2 more, by passing the arguments to Thread as positional args, rather than keyword arguments. \$\endgroup\$ May 19, 2012 at 20:51
  • 2
    \$\begingroup\$ Where is the code that deals with thread safety? You just fire threads hoping they'll run in the same order you start them. This won't always be true and is in fact the "hard part" of this problem. Instead of optimizing your program size you should re-consider the problem: you didn't get it in the first place. See gist.github.com/2761278 for a proof that this code doesn't work. \$\endgroup\$
    – silviot
    May 21, 2012 at 8:57
  • \$\begingroup\$ Quick fix. Use threading.Timer instead of threading.Thread. Pass in x as the sleep parameter. \$\endgroup\$ May 21, 2012 at 23:58
  • 1
    \$\begingroup\$ Joel's suggestion can be improved by 4 to for x in range(11):t.Timer(x,sys.stdout.write,"Hello World"[x]).start() \$\endgroup\$ May 22, 2012 at 7:16
  • 1
    \$\begingroup\$ @silviot: I was exploiting the fact that thread creation involves instantiating an object, and thus takes one- to two-thirds of a millisecond on the systems I've tested. Character output does not have this overhead, taking only a tenth of this time. Therefore, it will "always" work, as long as you don't override anything. Stdout is buffered so that shouldn't ever give problems either. \$\endgroup\$
    – marinus
    May 22, 2012 at 20:00
4
\$\begingroup\$

C# 73

"hello world".ToList().ForEach(c=>Task.Run(()=>Console.Write(c)).Wait());
\$\endgroup\$
2
  • \$\begingroup\$ not sure this satisfies the requirement that each letter be printed via its own thread since the tpl may reuse threads. \$\endgroup\$ May 20, 2012 at 16:15
  • \$\begingroup\$ In theory you're right, but on my pc ThreadPool.GetMaxThreads or ThreadPool.GetAvailableThreads returns a value around 1000 for both IO and worker threads. \$\endgroup\$
    – JJoos
    May 20, 2012 at 16:48
4
\$\begingroup\$

APL (Dyalog Unicode), 28 bytesSBCS

Full program. Prints to stderr. Inspired by marinus' solution.

'Hello World'{⍞←⍺⊣⎕DL⍵}&¨⍳11

Try it online!

⍳11 first 11 integers

'Hello World'{}&¨ for each integer as right argument (), spawn the following function with the corresponding character as left argument ():

⎕DL⍵delay right-argument seconds

⍺⊣ discard that (the effective delay) in favour of the left-argument character

⍞← print that to stdout without trailing line break

\$\endgroup\$
3
  • \$\begingroup\$ how about ⍞∘←&¨'dlroW olleH'? - I don't know if it's guaranteed theoretically but it seems to always print them in the correct order \$\endgroup\$
    – ngn
    Jul 30, 2018 at 8:26
  • \$\begingroup\$ @ngn Obviously, as there's no guarantee that the threads will operate in the order you start them, you have to make your program thread safe to ensure the output is printed in the right order. \$\endgroup\$
    – Adám
    Jul 30, 2018 at 9:20
  • \$\begingroup\$ that's the constraint I was trying to address, it might be guaranteed. I ran this 100 times and it looks like the thread scheduler always picks up the threads in reverse order. Or at least that's the case when there are ≤11 tasks. AFAIK ⍞∘← is not interruptible (or is it? maybe you can ask a C developer?). Dyalog implements green threads - 1 real thread pretending to be many, so if a (green) thread switch cannot occur, the order is predictable. \$\endgroup\$
    – ngn
    Jul 30, 2018 at 16:49
3
\$\begingroup\$

Java (160 chars)

class A{static int i;public static void main(String...a){new Thread(){public void run(){System.out.print("Hello World".charAt(i++));if(i<11)main();}}.start();}}

Yeah, I know this is the wrong language for code golf, I do it for fun.

\$\endgroup\$
11
  • \$\begingroup\$ class A{public static void main(String[]args){new B(0).start();}}class B extends Thread{int i;B(int j){i=j;}public void run(){System.out.print("Hello World".charAt(i));if(i<10)new B(i+1).start();}}-197 chars \$\endgroup\$ May 20, 2012 at 16:13
  • \$\begingroup\$ @Prince Yep, thanks for the correction! \$\endgroup\$
    – Malcolm
    May 20, 2012 at 19:23
  • \$\begingroup\$ class A extends Thread{static int i;public static void main(String[]args){System.out.print("Hello World".charAt(i++));if(i<11)new A().start();}public void run(){main(null);}} - 174 chars \$\endgroup\$ May 20, 2012 at 21:04
  • \$\begingroup\$ @Wouter Very good one! I totally missed it. \$\endgroup\$
    – Malcolm
    May 20, 2012 at 21:12
  • 1
    \$\begingroup\$ @Malcolm,@bkil,@Wouter: class A{static int i;public static void main(String...a){new Thread(){public void run(){System.out.print("Hello World".charAt(i++));if(i<11)main();}}.start();}} - 160 chars \$\endgroup\$ May 22, 2012 at 4:25
2
\$\begingroup\$

Bash (64)

:(){ [ "$1" ]&&(echo -n "${1:0:1}"&: "${1:1}")};: "Hello World"
\$\endgroup\$
2
  • \$\begingroup\$ @marinus Golfed doen by 3 chars: :()([ "$1" ]&&(printf "${1:0:1}"&: "${1:1}"));: Hello\ World \$\endgroup\$ Mar 17, 2014 at 21:33
  • \$\begingroup\$ @fossilet Works for me on both Linux and OSX, several bash versions. The last one or two characters is sometimes printed after the shell prompt. \$\endgroup\$ Mar 17, 2014 at 21:36
2
\$\begingroup\$

Haskell (120 118)

import Control.Concurrent
t=threadDelay.(*3^8)
main=(\(x,y)->forkIO$t x>>putChar y)`mapM_`zip[0..]"Hello World">>t 99

I'm not all that sure about multiplying by 9999 - I have a 2Ghz Xeon on which it'll work fine even if you don't, but I also have a Pentium 4 that needs it (999 gave garbled output and 99 didn't do anything at all.)

\$\endgroup\$
3
  • \$\begingroup\$ Save 2 characters by using (*5^6) instead of (*9999) and not using backquotes for mapM_. \$\endgroup\$ May 19, 2012 at 21:14
  • \$\begingroup\$ @Mechanicalsnail If you remove the backticks you need an extra pair of braces, otherwise it parses as (((mapM_ (\(x,y) ... )) zip) [0..]) ... which you don't want. \$\endgroup\$
    – marinus
    May 19, 2012 at 21:46
  • \$\begingroup\$ As for 999, it might be getting truncated to 0 due to operating system limitations, but I could be wrong. What OS are you using? \$\endgroup\$
    – Joey Adams
    May 22, 2012 at 21:58
2
\$\begingroup\$

scala(81 79 chars)

def?(l:String){if(l.size!=0)new Thread{print(l(0));?(l.tail)}}
?("Hello World")
\$\endgroup\$
2
  • \$\begingroup\$ A little bit shorter: def?(l:String){if(l.size>0)new Thread{print(l(0));?(l.tail)}} \$\endgroup\$
    – Joa Ebert
    May 20, 2012 at 10:03
  • \$\begingroup\$ @JoaEbert:yea,nice \$\endgroup\$ May 20, 2012 at 14:45
2
\$\begingroup\$

Groovy, 51 characters

"Hello World".each{a->Thread.start{print a}.join()}
\$\endgroup\$
1
\$\begingroup\$

D (135 chars)

import std.concurrency,std.stdio;
void main(){
    p("Hello World");
}
void p(string h){
    write(h[0]);
    if(h.length>1)spawn(&p,h[1..$]);
}

I only start the next thread when I have already printed the current char

edit +2 chars for better bound check

\$\endgroup\$
2
  • \$\begingroup\$ I get [email protected](6): Range violation error. \$\endgroup\$ May 19, 2012 at 15:09
  • \$\begingroup\$ @fossilet I fixed it \$\endgroup\$ May 19, 2012 at 15:44
1
\$\begingroup\$

Scala 74

"Hello World".zipWithIndex.par.map(x=>{Thread.sleep(x._2*99);print(x._1)})
  • zipWithIndex produces ((H, 0), (e, 1), (l, 2) ...).
  • par makes it a parallel collection.

Tests:

(1 to 10).foreach {_ => "Hello World".zipWithIndex.par.map(x=>{Thread.sleep(x._2*99);print(x._1)});println()}
Hello World
Hello World
Hello World
...
Hello World
\$\endgroup\$
8
  • \$\begingroup\$ scala> "Hello World".zipWithIndex.par.foreach(x=>{Thread.sleep(x._2*99);print(x._1)}) Hel lWrolod - I got this \$\endgroup\$ May 20, 2012 at 1:19
  • \$\begingroup\$ Also println(Thread.currentThread.getName) shows that the threads are not unique. \$\endgroup\$ May 20, 2012 at 1:23
  • \$\begingroup\$ @PrinceJohnWesley: I guess you need one core per letter, so that par will distribute the work over all cores. \$\endgroup\$ May 20, 2012 at 1:24
  • \$\begingroup\$ I got it. so one core per letter + high resolution of the system clock required. \$\endgroup\$ May 20, 2012 at 1:31
  • \$\begingroup\$ use map instead of foreach. you can save 4 characters. \$\endgroup\$ May 20, 2012 at 1:32
1
\$\begingroup\$

Javascript (72)

(function f(){console.log("Hello world"[i++]);i<11&&setTimeout(f)})(i=0)
\$\endgroup\$
1
\$\begingroup\$

scala(45)

Thread#join based solution

"Hello World"map{x=>new Thread{print(x)}join}

or

for(x<-"Hello World")new Thread{print(x)}join
\$\endgroup\$
1
\$\begingroup\$

This is my F# attempt. My first serious F# program. Please be kind.

let myprint c = async {
        printfn "%c"c
}
"Hello World"|>Seq.map myprint|>Async.Parallel|>Async.RunSynchronously|>ignore
\$\endgroup\$
0
\$\begingroup\$

Go

package main
import"fmt"
func main(){o:=make(chan int)
for _,c:=range"Hello World"{go func(c rune){fmt.Printf("%c",c)
o<-0}(c)}
for i:=0;i<11;i++{<-o}}
\$\endgroup\$
1
  • \$\begingroup\$ You don't need to count the characters - we will do so for you! \$\endgroup\$ May 20, 2012 at 1:35
0
\$\begingroup\$

Erlang (90)

-module(h).
r()->r("Hello World").
r([])->'';r([H|T])->spawn(h,r,[T]),io:format("~c",[H]).

Compile erlc +export_all h.erl

\$\endgroup\$
0
\$\begingroup\$

Nimrod, 121

proc p(c:char){.thread.}=write(stdout,c)
for c in "Hello World":
 var t:TThread[char]
 createThread(t,p,c)
 joinThread(t)
\$\endgroup\$
0
\$\begingroup\$

Python: too many characters, but it works.

# Ok. First we patch Threading.start to test wether our solution actually works

import threading
import random, time
original_run = threading.Thread.run


def myRun(self):
    tosleep = random.randint(0,200)/1000.0
    time.sleep(tosleep)
    original_run(self)

threading.Thread.run = myRun

# And now the real code:
import time, sys, threading
string_to_write = "Hello World\n"
current_char_index = 0 # This integer represents the index of the next char to be written
# It will act as a semaphore: threads will wait until it reaches
# the index of the single char that particular thread is due to output

class Writer(threading.Thread):
    def __init__(self, char_to_write, index_to_write):
        self.char_to_write, self.index_to_write = char_to_write, index_to_write
        super(Writer, self).__init__()
    def run(self):
        ch = globals()['current_char_index']
        while not self.index_to_write == ch:
            time.sleep(0.005)
        sys.stdout.write(self.char_to_write)
        # This will be atomic because no other thread will touch it while it has "our" index
        globals()['current_char_index'] += 1

for i, char in enumerate(string_to_write):
    Writer(char, i).start()
\$\endgroup\$
2
  • \$\begingroup\$ I don't understand what the purpose of randomizing sleep time is. \$\endgroup\$ May 22, 2012 at 18:19
  • \$\begingroup\$ @Joel to ensure that, when it works, it's not a lucky coincidence of the threads being executed in the same order as they were fired. \$\endgroup\$
    – silviot
    Jun 12, 2012 at 13:45
0
\$\begingroup\$

C# 90 84

foreach(var c in"Hello World"){var t=new Thread(Console.Write);t.Start(c);t.Join();}

Running version: http://ideone.com/0dXNw

\$\endgroup\$
2
  • \$\begingroup\$ console.write is very fast which is why this may work for you but is definitely not thread safe! \$\endgroup\$ May 20, 2012 at 16:17
  • \$\begingroup\$ @statichippo you're right; I fixed that. \$\endgroup\$ May 20, 2012 at 17:09
0
\$\begingroup\$

Objective-C (183 characters)

-(void) thread {[self performSelectorInBackground:@selector(printC) withObject:nil];}
-(void) printC {char *c = "Hello World"; for(int i = 0; c[i] != '\0'; i++) {printf("%c", c[i]);}}
\$\endgroup\$
0
\$\begingroup\$

Haskell 99 Characters

import Control.Concurrent
f[]=return()
f(x:xs)=(putChar x)>>(forkIO$f xs)>>f[]
main=f"Hello World"

How it works is each thread starts the next after having displayed its character, so they actually useful stuff can not happen out of sequence.

\$\endgroup\$
0
\$\begingroup\$

Bash, 43 bytes

xargs -n1 printf<<<'H e l l o \  W o r l d'

Try it online!

xargs forks a separate printf process for each character (and waits for it to exit).

Bash, 45 bytes, no external utilities

eval \(printf\ {H,e,l,l,o,\\\ ,W,o,r,l,d}\)\;

Try it online!

Expands to (printf H); (printf e); (printf l); (printf l); (printf o); (printf \ ); (printf W); (printf o); (printf r); (printf l); (printf d); before evaluation. The parentheses make Bash fork a subshell for each letter (and wait for it to exit), but this time printf is the Bash builtin.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.