HelolW rdlo (Una sfida al threading)


39

Ho una sfida per te:

  • Stampa "Hello World" con qualsiasi lingua.
  • Ogni personaggio deve essere stampato dal proprio thread unico

Questo è tutto. Ovviamente, poiché non vi è alcuna garanzia che i thread funzioneranno nell'ordine in cui li si avvia, è necessario rendere sicuro il thread del programma per garantire che l'output sia stampato nell'ordine giusto.

E, poiché si tratta di code golf, vince il programma più breve.

Aggiornare:

Il vincitore è l'ingresso APL di Marinus , con 34 caratteri. Inoltre vince il premio per l'ingresso meno leggibile.


10
Un nome migliore per questo sarebbe statoHelolW rdlo
Cristian Lupascu

Ah, mi piace. Cambiandolo subito: D
Tharwen,

Aww ... è troppo corto
Tharwen,

1
È divertente vedere quante persone ignorano il suggerimento "ovviamente, poiché non vi è alcuna garanzia che i thread funzioneranno nell'ordine in cui li si avvia" suggerimento e pensare che abbiano capito bene.
Joa Ebert,

Anche se è vero che "non vi è alcuna garanzia che i thread funzioneranno nell'ordine in cui li si avvia" in pratica lo faranno quasi sempre per un programma così banale. Per evitare questa confusione aggiungerei al problema che ogni thread deve 1) attendere un (piccolo) numero casuale di millisecondi 2) emettere il suo carattere 3) attendere un altro tempo casuale (forse lungo) In questo modo le persone potrebbero dire se il codice funziona semplicemente eseguendolo un paio di volte. E le soluzioni join () avrebbero prestazioni molto peggiori. Senza l'attesa casuale uno potrebbe essere fuorviato da una corsa di successo per pensare che il suo programma sia corretto.
Silviot,

Risposte:


10

APL (Dyalog) ( 44 43 39 34)

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

Spiegazione:

  • 2 11⍴'Hello World',⍳11 crea una matrice: (H, 1), (e, 2), ...
  • &⌿ significa: per ogni colonna della matrice, eseguire su un thread separato:
  • In un thread, ora è il personaggio e ora è il momento
  • ⎕DL⊃⍵aspetta secondi.
  • Quindi, ⍞←⍺genera il personaggio.

11
Sai cosa? Prenderò la tua parola per questo ... :)
Bolster

OK, questo è il più breve. Congratulazioni!
Tharwen,

19

C, 61 62 caratteri

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

Le funzioni della libreria pthread hanno tutti nomi luccicanti, quindi ho attivato un intero processo separato per ogni personaggio. fork()è molto più breve.

È stato necessario utilizzare write()anziché putchar()perché le funzioni di buffering stdio non sono thread-safe.

Modificato : backup fino a 62 caratteri. Nel mio zelo, anche scendere a 61 caratteri ha lasciato cadere la sicurezza del thread.


Dovrebbe essere possibile modificare l'istruzione write in write(1,"Hello World\n",!!++i)per 2 byte. Bella soluzione altrimenti.
primo

Dovresti provarlo e vedere cosa produce.
breadbox

Per errore, intendevo!!++i
primo

Sembra essere quello che hai scritto la prima volta, quindi non vedo quale errore stavi cercando di correggere. E non ero faceto: intendevo sinceramente che dovresti provarlo tu stesso e vedere cosa succede. Rimuovendo l'aggiunta, ogni thread stamperà solo il primo carattere della stringa.
breadbox,

Inizialmente avevo scritto !!i++, ma l'ho modificato pochi secondi dopo, perché mi sono reso conto che avrebbe valutato 0la prima iterazione. Presumo che tu abbia visto la versione inedita. Non sono in grado di testare il tuo codice, perché stampa solo il primissimo carattere, una volta . Ci sono molte alternative però; i++<13, usando !!io anchewrite(1,"Hello World\n",i++>13||fork()||main())
primo

9

Rubino, 46 ​​caratteri

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

È sincronizzato a causa del fatto che il programma attende la fine del thread prima di iniziare il thread successivo e continuare con il carattere successivo.


7

Pythonect (35 caratteri)

http://www.pythonect.org

"Hello World"|list|_.split()->print

Questo è il più breve finora. Dal momento che non ho idea di cosa faccia effettivamente, supporrò che sia corretto e lo accetterò tra un giorno o due se nessuno ci parla contro o pubblica qualcosa di più breve.
Tharwen,

1
Ho appena dato una breve occhiata agli esempi. L'istruzione print o statement list non dovrebbe contenere parentesi []?
Dalin Seivewright,

1
Ciao, sto trasmettendo la risposta di Itzik (creatore di pythonect): '->' e '|' sono entrambi operatori Pythonect. L'operatore pipe passa un articolo su un articolo, mentre l'altro operatore passa tutti gli oggetti contemporaneamente. Ciò che fa il programma sopra è, prende la stringa "Hello World", lo trasforma in un elenco, divide l'elenco in caratteri e invia ogni carattere per la stampa. È possibile ottimizzare ulteriormente il programma, come segue: iter ("Hello World") | print Ciò che fa è, itera la stringa "Hello World" e invia ogni carattere alla stampa (in modo sincronizzato / bloccante). Saluti, Itzik Kotler | ikotler.org
Leon Fedotov

come viene fatto il threading qui ???
Rohit,

1
Come menzionato @LeonFedotov e dalla fonte pythonect (disponibile su pythonect ) dopo l'analisi, per ogni iterazione e l'operatore '->', il threading viene eseguito in questo modo: thread = threading.Thread (target = __ run, args = ([( operatore, oggetto)] + espressione [1:], copy.copy (globals_), copy.copy (locals_), return_value_queue, not iterate_literal_arrays)) thread.start ()
Jonathan Rom

6

Python ( 101 93 98)

Questa è la soluzione di Peter Taylor. Funziona ritardando la stampa dell'N-esimo carattere di N secondi. Vedi commenti

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

Questo è quello originale:

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

Ha funzionato perché il tempo necessario per stampare un singolo carattere è inferiore al tempo impiegato da Python per inizializzare un nuovo thread, pertanto l'N-esimo thread sarebbe terminato prima della creazione dell'N + 1 ° thread. Apparentemente è contro le regole fare affidamento su questo.


Puoi salvare 3 caratteri cambiando import sys,threadingin import sys,threading as te puoi salvarne altri 2, passando gli argomenti a Thread come argomenti posizionali, piuttosto che argomenti di parole chiave.
Joel Cornett,

2
Dov'è il codice che si occupa della sicurezza dei thread? Sparisci solo fili sperando che corrano nello stesso ordine in cui li avvii. Questo non sarà sempre vero ed è in effetti la "parte difficile" di questo problema. Invece di ottimizzare le dimensioni del programma, dovresti riconsiderare il problema: non l'hai capito in primo luogo. Vedi gist.github.com/2761278 per una prova che questo codice non funziona.
Silviot,

Soluzione rapida. Usa threading.Timerinvece di threading.Thread. Passa xcome parametro sleep.
Joel Cornett,

1
Il suggerimento di Joel può essere migliorato di 4 afor x in range(11):t.Timer(x,sys.stdout.write,"Hello World"[x]).start()
Peter Taylor

1
@silviot: stavo sfruttando il fatto che la creazione di thread comporta l'istanza di un oggetto e quindi impiega da uno a due terzi di millisecondo sui sistemi che ho testato. L'output del personaggio non ha questo sovraccarico, impiegando solo un decimo di questo tempo. Pertanto, funzionerà "sempre", purché non si ignori alcunché. Stdout è bufferizzato, quindi non dovrebbe mai dare problemi.
Marinus

4

C # 73

"hello world".ToList().ForEach(c=>Task.Run(()=>Console.Write(c)).Wait());

non sono sicuro che questo soddisfi il requisito per cui ogni lettera deve essere stampata tramite il proprio filo poiché il tpl può riutilizzare i fili.
statichippo,

In teoria hai ragione, ma sul mio PC ThreadPool.GetMaxThreads o ThreadPool.GetAvailableThreads restituisce un valore di circa 1000 per entrambi i thread IO e worker.
JJoos,

4

APL (Dyalog Unicode) , SBCS da 28 byte

Programma completo. Stampa su stderr. Ispirato alla soluzione di Marinus .

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

Provalo online!

⍳11 primi 11 numeri interi

'Hello World'{... }&¨ per ogni numero intero come argomento a destra ( ), genera la seguente funzione con il carattere corrispondente come argomento a sinistra ( ):

⎕DL⍵d e l ay destro argomenti secondi

⍺⊣ scartare quello (il ritardo effettivo) a favore del carattere di argomento sinistro

⍞← stampalo su stdout senza interruzione di riga finale


che ne dici ⍞∘←&¨'dlroW olleH'? - Non so se sia teoricamente garantito, ma sembra stamparli sempre nell'ordine corretto
ngn

@ngn Ovviamente, poiché non vi è alcuna garanzia che i thread funzionino nell'ordine in cui li si avvia, è necessario rendere sicuro il thread del programma per garantire che l'output sia stampato nell'ordine giusto.
Adám,

questo è il vincolo che stavo cercando di affrontare, potrebbe essere garantito. L'ho eseguito 100 volte e sembra che l'utilità di pianificazione dei thread raccolga sempre i thread in ordine inverso. O almeno questo è il caso di compiti ≤11. AFAIK ⍞∘←non è interrompibile (o lo è? Forse puoi chiedere a uno sviluppatore C?). Dyalog implementa thread verdi - 1 thread reale che finge di essere molti, quindi se non è possibile un cambio di thread (verde), l'ordine è prevedibile.
ngn,

3

Java (160 caratteri)

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

Sì, so che questa è la lingua sbagliata per il golf del codice, lo faccio per divertimento.


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 personaggi
Prince John Wesley,

@Prince Sì, grazie per la correzione!
Malcolm,

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 caratteri
Wouter Coekaerts

@Wouter Molto buono! L'ho perso del tutto.
Malcolm,

1
@ 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 caratteri
Prince John Wesley,

2

Bash (64)

:(){ [ "$1" ]&&(echo -n "${1:0:1}"&: "${1:1}")};: "Hello World"

@marinus Golfed doen by 3 chars::()([ "$1" ]&&(printf "${1:0:1}"&: "${1:1}"));: Hello\ World
Digital Trauma

@fossilet Funziona per me su Linux e OSX, diverse versioni bash. L'ultimo uno o due caratteri viene talvolta stampato dopo il prompt della shell.
Trauma digitale

2

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

Non sono così sicuro di moltiplicare per 9999: ho un Xeon da 2 Ghz su cui funzionerà benissimo anche se non lo fai, ma ho anche un Pentium 4 che ne ha bisogno (999 ha prodotto un risultato confuso e 99 no) non fare nulla.)


Salva 2 caratteri usando (*5^6)invece di (*9999)e non usando i backquotes per mapM_.
Lumaca meccanica,

@Mechanicalsnail Se rimuovi i backtick hai bisogno di un paio di parentesi graffe, altrimenti analizza ciò (((mapM_ (\(x,y) ... )) zip) [0..]) ...che non vuoi.
marinus,

Per quanto riguarda 999, potrebbe essere troncato a 0 a causa delle limitazioni del sistema operativo, ma potrei sbagliarmi. Quale sistema operativo stai usando?
Joey Adams,

2

scala ( 81 79 caratteri)

def?(l:String){if(l.size!=0)new Thread{print(l(0));?(l.tail)}}
?("Hello World")

Un po 'più breve: def? (L: String) {if (l.size> 0) new Thread {print (l (0));? (L.tail)}}
Joa Ebert,

@JoaEbert: sì, carino
Prince John Wesley,

2

Groovy, 51 personaggi

"Hello World".each{a->Thread.start{print a}.join()}

1

D (135 caratteri)

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..$]);
}

Inizio il thread successivo solo quando ho già stampato il carattere corrente

modifica +2 caratteri per un migliore controllo associato


Ottengo l' core.exception.RangeError@test.d(6): Range violationerrore.
Fish Monitor,

@fossilet l'ho risolto
maniaco del cricchetto,

1

Scala 74

"Hello World".zipWithIndex.par.map(x=>{Thread.sleep(x._2*99);print(x._1)})
  • zipWithIndex produce ((H, 0), (e, 1), (l, 2) ...).
  • par lo rende una raccolta parallela.

test:

(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

scala> "Hello World".zipWithIndex.par.foreach(x=>{Thread.sleep(x._2*99);print(x._1)}) Hel lWrolod- Ho capito
principe John Wesley

println(Thread.currentThread.getName)Mostra anche che i thread non sono univoci.
Prince John Wesley,

@PrinceJohnWesley: immagino tu abbia bisogno di un core per lettera, in modo che il par distribuisca il lavoro su tutti i core.
utente sconosciuto

Capito. quindi è richiesto un core per lettera + alta risoluzione dell'orologio di sistema.
Prince John Wesley,

utilizzare mapinvece di foreach. puoi salvare 4 caratteri.
Prince John Wesley,

1

Javascript (72)

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

1

scala (45)

Discussione # soluzione basata su join

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

o

for(x<-"Hello World")new Thread{print(x)}join

1

Questo è il mio tentativo di F #. Il mio primo serio programma F #. Per favore sii gentile.

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

0

Partire

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

Non è necessario contare i personaggi: lo faremo per te!
utente sconosciuto

0

Erlang (90)

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

Compilare erlc +export_all h.erl



0

Python: troppi personaggi, ma funziona.

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

Non capisco quale sia lo scopo di randomizzare il tempo di sonno.
Joel Cornett,

@Joel per assicurarsi che, quando funziona, non è una coincidenza fortunata che i thread vengano eseguiti nello stesso ordine in cui sono stati licenziati.
Silviot,


0

Objective-C (183 caratteri)

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

0

Personaggi di Haskell 99

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

Come funziona è che ogni thread inizia il successivo dopo aver mostrato il suo carattere, quindi in realtà cose utili non possono accadere fuori sequenza.


0

Bash , 43 byte

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

Provalo online!

xargsprevede un printfprocesso separato per ogni personaggio (e attende che esca).

Bash , 45 byte, nessuna utility esterna

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

Provalo online!

Si espande (printf H); (printf e); (printf l); (printf l); (printf o); (printf \ ); (printf W); (printf o); (printf r); (printf l); (printf d);prima della valutazione. Le parentesi rendono Bash fork una subshell per ogni lettera (e attendono che esca), ma questa volta printfè incorporato in Bash.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.