HelolW rdlo (Un défi de threading)


39

J'ai un challenge pour toi:

  • Imprimez "Hello World" en utilisant n'importe quelle langue.
  • Chaque caractère doit être imprimé à partir de son propre fil unique

C'est ça. Bien entendu, comme il n’est pas garanti que les threads fonctionneront dans l’ordre dans lequel vous les avez démarrés, vous devez sécuriser votre thread de programme pour que le résultat soit imprimé dans le bon ordre.

Et, parce que c'est du golf de code, le programme le plus court gagne.

Mise à jour:

Le gagnant est l’entrée APL de Marinus , avec 34 caractères. Il remporte également le prix de l'entrée la moins lisible.


10
Un meilleur nom pour cela aurait étéHelolW rdlo
Cristian Lupascu

Ha, j'aime ça. Le changer tout de suite: D
Tharwen

Aww ... c'est trop court
Tharwen

1
Il est amusant de voir combien de personnes ignorent l'indication "de toute évidence, car rien ne garantit que les threads fonctionneront dans l'ordre dans lequel vous les démarrez" et que vous pensez qu'ils ont bien compris.
Joa Ebert

Même s’il est vrai que "rien ne garantit que les threads fonctionneront dans l’ordre dans lequel vous les démarrez", ils le feront presque toujours pour un programme aussi trivial. Pour éviter cette confusion, je voudrais ajouter au problème que chaque thread doit 1) attendre un (petit) nombre aléatoire de millisecondes 2) afficher son caractère 3) attendre un autre laps de temps aléatoire (peut-être long) Ainsi, les gens pourraient dire si le code fonctionne simplement en l'exécutant quelques fois. Et les solutions join () seraient beaucoup moins performantes. Sans attente aléatoire, on pourrait être trompé par une course réussie en pensant que son programme est correct.
Silviot

Réponses:


10

APL (Dyalog) ( 44 43 39 34)

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

Explication:

  • 2 11⍴'Hello World',⍳11 crée une matrice: (H, 1), (e, 2), ...
  • &⌿ signifie: pour chaque colonne de la matrice, faites sur un thread séparé:
  • Dans un fil, c'est maintenant le personnage et c'est maintenant le moment
  • ⎕DL⊃⍵attend des secondes.
  • Puis, ⍞←⍺sort le caractère.

11
Vous savez quoi? Je te crois sur parole ... :)
Sellette

OK, c'est le plus court. Toutes nos félicitations!
Tharwen

19

C, 61 62 caractères

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

Les fonctions de la bibliothèque pthread ont toutes un nom loooooong. J'ai donc lancé un processus distinct pour chaque caractère. fork()est tellement plus courte.

Il était nécessaire d'utiliser à la write()place de putchar()parce que les fonctions de tampon stdio ne sont pas thread-safe.

Édité : Sauvegarde jusqu'à 62 caractères. Dans mon zèle, le fait de descendre à 61 caractères a également fait tomber le filet de sécurité.


Il devrait être possible de changer l'instruction write en write(1,"Hello World\n",!!++i)2 octets. Belle solution sinon.
Primo

Vous devriez essayer cela et voir ce que cela produit.
breadbox

Mon erreur, je voulais dire!!++i
primo

Cela semble être ce que vous avez écrit la première fois, alors je ne vois pas quelle erreur vous tentiez de corriger. Et je n'étais pas facétieux: honnêtement, je voulais dire que vous devriez essayer vous-même et voir ce qui se passe. En supprimant l'ajout, chaque thread imprimera simplement le premier caractère de la chaîne.
breadbox

J'avais initialement écrit !!i++, mais je l'ai édité quelques secondes plus tard, car je me suis rendu compte que l'évaluation se ferait à 0la première itération. J'ai supposé que vous aviez vu la version non éditée. Je ne suis pas en mesure de tester votre code, car il n'imprime le premier caractère, une fois . Il y a beaucoup d'alternatives cependant; i++<13, en utilisant !!i, ou mêmewrite(1,"Hello World\n",i++>13||fork()||main())
primo

9

Ruby, 46 personnages

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

Il est synchronisé car le programme attend la fin du thread avant de démarrer le prochain thread et de continuer avec le caractère suivant.


7

Pythonect (35 caractères)

http://www.pythonect.org

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

C'est le plus court jusqu'à présent. N'ayant aucune idée de ce qu'il fait réellement, je vais supposer que c'est correct et l'accepter dans un jour ou deux si personne ne le dit ou ne publie rien de plus court.
Tharwen

1
Je viens d'avoir un bref aperçu des exemples. Les instructions print ou list ne doivent-elles pas être entourées de crochets []?
Dalin Seivewright

1
Bonjour, dans la transmission de Itzik (créateur de pythonect), répondez: '->' et '|' sont les deux opérateurs Pythonect. L'opérateur de pipe passe un élément à un article, tandis que l'autre opérateur passe tous les articles à la fois. Le programme ci-dessus ne prend que la chaîne "Hello World", la transforme en liste, scinde la liste en caractères et envoie chaque caractère à imprimer. Il est possible d'optimiser encore plus le programme, par exemple: iter ("Hello World") | print De quoi il s'agit, il itère la chaîne "Hello World" et envoie chaque caractère à imprimer (de manière synchrone / bloquante). Cordialement, Itzik Kotler | ikotler.org
Leon Fedotov

comment se fait le filetage ici ???
Rohit

1
Comme @LeonFedotov mentionné, et à partir de la source pythonect (disponible sur pythonect ) après l'analyse, pour chaque itération et l'opérateur '->', le threading est fait comme ceci: thread = threading.Thread (target = __ run, args = (( opérateur, item)] + expression [1:], copy.copy (globals_), copy.copy (locals_), return_value_queue, not iterate_literal_arrays)) thread.start ()
Jonathan Rom

6

Python ( 101 93 98)

C'est la solution de Peter Taylor. Cela fonctionne en retardant l'impression du Nième caractère de N secondes. Voir les commentaires.

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

C'est l'original:

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

Cela a fonctionné, car le temps nécessaire pour imprimer un seul caractère est inférieur au temps nécessaire à l'initialisation d'un nouveau thread par Python. Le N-ème thread s'achèverait donc avant la création du N-1-ème thread. Apparemment, il est contraire aux règles de s'en prévaloir.


Vous pouvez enregistrer 3 caractères en changeant import sys,threadingen import sys,threading as tet vous pouvez en enregistrer 2 autres, en transmettant les arguments à Thread sous forme d'arguments de position, plutôt que d'arguments de mot clé.
Joel Cornett

2
Où est le code qui traite de la sécurité des threads? Vous tirez simplement sur les threads en espérant qu'ils fonctionneront dans le même ordre que vous les démarrez. Ce ne sera pas toujours vrai et est en fait la "partie difficile" de ce problème. Au lieu d'optimiser la taille de votre programme, vous devriez reconsidérer le problème: vous ne l'avez pas compris. Voir gist.github.com/2761278 pour une preuve que ce code ne fonctionne pas.
Silviot

Solution rapide. Utilisez threading.Timerau lieu de threading.Thread. Passer en xtant que paramètre de sommeil.
Joel Cornett

1
La suggestion de Joel peut être améliorée de 4 àfor x in range(11):t.Timer(x,sys.stdout.write,"Hello World"[x]).start()
Peter Taylor

1
@silviot: J'exploitais le fait que la création d'un fil implique l'instanciation d'un objet et prend donc un à deux tiers de milliseconde sur les systèmes que j'ai testés. La sortie de personnage n'a pas cette surcharge, prenant seulement un dixième de ce temps. Par conséquent, cela fonctionnera "toujours", tant que vous ne remplacerez rien. Stdout est en mémoire tampon, cela ne devrait donc pas poser de problèmes non plus.
marinus

4

C # 73

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

Je ne suis pas sûr que cela réponde à l'exigence voulant que chaque lettre soit imprimée via son propre fil, car le tpl peut réutiliser des fils.
statichippo

En théorie, vous avez raison, mais sur mon pc ThreadPool.GetMaxThreads ou ThreadPool.GetAvailableThreads renvoie une valeur autour de 1000 pour les threads IO et de travail.
JJoos

4

APL (Dyalog Unicode) , SBCS sur 28 octets

Programme complet. Imprime sur stderr. Inspiré par la solution de marinus .

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

Essayez-le en ligne!

⍳11 11 premiers entiers

'Hello World'{}&¨ Pour chaque entier sous forme d'argument de droite ( ), créez la fonction suivante avec le caractère correspondant sous forme d'argument de gauche ( ):

⎕DL⍵d e l ay des secondes d'argument juste

⍺⊣ rejeter que (le délai effectif) en faveur du caractère d'argument de gauche

⍞← imprimer cela sur stdout sans fin de ligne


que diriez- ⍞∘←&¨'dlroW olleH'vous - Je ne sais pas si c'est garanti en théorie mais cela semble toujours les imprimer dans le bon ordre
ngn

@ngn Evidemment, comme il n'y a aucune garantie que les threads fonctionneront dans l'ordre dans lequel vous les démarrez, vous devez sécuriser votre thread de programme pour garantir que le résultat est imprimé dans le bon ordre.
Adám

c'est la contrainte que j'essayais de résoudre, cela pourrait être garanti. J'ai couru cela 100 fois et il semble que le planificateur de threads prenne toujours les threads dans l'ordre inverse. Ou du moins c'est le cas lorsqu'il y a ≤11 tâches. AFAIK ⍞∘←n’est pas interruptible (ou peut-être pouvez-vous demander à un développeur C?). Dyalog implémente des threads verts - 1 vrai thread prétendant être multiple. Par conséquent, si un commutateur de threads (vert) ne peut pas se produire, l'ordre est prévisible.
ngn

3

Java (160 caractères)

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

Oui, je sais que c'est la mauvaise langue pour le code golf, je le fais pour le plaisir.


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 caractères
Prince John Wesley

@Prince Yep, merci pour la correction!
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 caractères
Wouter Coekaerts

@Wouter Très bon! Cela m'a totalement manqué.
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 caractères
Prince John Wesley

2

Bash (64)

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

@marinus Jouer au golf par 3 caractères::()([ "$1" ]&&(printf "${1:0:1}"&: "${1:1}"));: Hello\ World
Digital Trauma

@fossilet Fonctionne pour moi sous Linux et OSX, plusieurs versions bash. Les derniers caractères sont parfois imprimés après l’invite du shell.
Digital Trauma

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

Je ne suis pas sûr de pouvoir multiplier par 9999 - j'ai un Xeon 2Ghz qui fonctionnera bien même si vous ne le faites pas, mais j'ai aussi un Pentium 4 qui en a besoin (999 donne une sortie tronquée et 99 ne le sont pas. ne rien faire du tout.)


Enregistrez 2 caractères en utilisant (*5^6)plutôt que de (*9999)ne pas utiliser les citations arrières pour mapM_.
Escargot mécanique

@Mechanicalsnail Si vous supprimez les backticks, vous avez besoin d'une paire supplémentaire d'accolades. Sinon, l'analyse se (((mapM_ (\(x,y) ... )) zip) [0..]) ...fera comme vous ne le souhaitez pas.
marinus

En ce qui concerne 999, il pourrait être tronqué à 0 en raison de limitations du système d'exploitation, mais je peux me tromper. Quel système d'exploitation utilisez-vous?
Joey Adams

2

scala ( 81 79 caractères)

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

Un peu plus court: def? (L: String) {if (l.size> 0) nouveau Thread {print (l (0));? (L.tail)}}
Joa Ebert

@JoaEbert: oui, gentil
Prince John Wesley


1

D (135 caractères)

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

Je ne commence le prochain thread que lorsque j'ai déjà imprimé le caractère actuel

éditer +2 caractères pour un meilleur contrôle lié


J'ai une core.exception.RangeError@test.d(6): Range violationerreur.
Fish Monitor

@fossilet je l'ai corrigé
phénomène de cliquet

1

Scala 74

"Hello World".zipWithIndex.par.map(x=>{Thread.sleep(x._2*99);print(x._1)})
  • zipWithIndex produit ((H, 0), (e, 1), (l, 2) ...).
  • par en fait une collection parallèle.

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

scala> "Hello World".zipWithIndex.par.foreach(x=>{Thread.sleep(x._2*99);print(x._1)}) Hel lWrolod- J'ai eu ceci
Prince John Wesley

Indique également println(Thread.currentThread.getName)que les threads ne sont pas uniques.
Prince John Wesley

@PrinceJohnWesley: Je suppose que vous avez besoin d'un noyau par lettre pour que le pair distribue le travail sur tous les cœurs.
utilisateur inconnu

J? ai compris. il faut donc un cœur par lettre + une résolution élevée de l’horloge système.
Prince John Wesley

utiliser mapau lieu de foreach. vous pouvez enregistrer 4 caractères.
Prince John Wesley

1

Javascript (72)

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

1

Scala (45)

Thread # rejoindre la solution basée

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

ou

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

1

Ceci est ma tentative de F #. Mon premier programme F # sérieux. S'il vous plaît soyez gentil.

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

0

Aller

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

Vous n'avez pas besoin de compter les personnages - nous le ferons pour vous!
utilisateur inconnu

0

Erlang (90)

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

Compiler erlc +export_all h.erl



0

Python: trop de caractères, mais ça marche.

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

Je ne comprends pas le but de la randomisation du temps de sommeil.
Joel Cornett

@ Joel pour s'assurer que, lorsque cela fonctionne, ce n'est pas une coïncidence heureuse que les threads soient exécutés dans le même ordre qu'ils ont été renvoyés.
Silviot


0

Objective-C (183 caractères)

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

Haskell 99 personnages

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

Comment cela fonctionne-t-il? Chaque thread commence le suivant après avoir affiché son caractère, de sorte qu'il ne peut pas arriver que des choses utiles se déroulent dans le désordre.


0

Bash , 43 octets

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

Essayez-le en ligne!

xargsforks un printfprocessus séparé pour chaque caractère (et attend sa sortie).

Bash , 45 octets, aucun utilitaire externe

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

Essayez-le en ligne!

S'étend à (printf H); (printf e); (printf l); (printf l); (printf o); (printf \ ); (printf W); (printf o); (printf r); (printf l); (printf d);avant l'évaluation. Les parenthèses font de Bash un sous-shell pour chaque lettre (et attendent qu’elle se printftermine ), mais cette fois, c’est la fonction intégrée de Bash.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.