HelolW rdlo (wyzwanie dla wątków)


39

Mam dla ciebie wyzwanie:

  • Wydrukuj „Hello World” w dowolnym języku.
  • Każda postać musi być wydrukowana z własnego, unikalnego wątku

Otóż ​​to. Oczywiście, ponieważ nie ma gwarancji, że wątki będą działały w kolejności, w jakiej je uruchomiłeś, musisz zapewnić bezpieczeństwo swojego wątku programu, aby mieć pewność, że wydruk zostanie wydrukowany we właściwej kolejności.

A ponieważ jest to kod golfowy, wygrywa najkrótszy program.

Aktualizacja:

Zwycięzcą jest wpis APL Marinusa, składający się z 34 znaków. Wygrywa także nagrodę za najmniej czytelne zgłoszenie.


10
Lepszą nazwą byłoby toHelolW rdlo
Cristian Lupascu,

Ha, podoba mi się to. Zmiana od razu: D
Tharwen

Aww ... jest za krótki
Tharwen

1
Zabawne jest, jak wiele osób ignoruje „oczywiście, ponieważ nie ma gwarancji, że wątki będą działały w kolejności, w której je uruchomisz” podpowiedź i myślę, że mają rację.
Joa Ebert

Chociaż prawdą jest, że „nie ma gwarancji, że wątki będą działały w kolejności, w której je uruchomisz”, w praktyce prawie zawsze zrobią to dla tak trywialnego programu. Aby uniknąć tego zamieszania, dodałbym do problemu, że każdy wątek musi 1) poczekać (małą) losową liczbę milisekund 2) wypisać swój znak 3) poczekać na kolejny losowy (może długi) czas W ten sposób ludzie mogliby stwierdzić, czy kod działa, uruchamiając go kilka razy. A rozwiązania join () działałyby znacznie gorzej. Bez przypadkowego oczekiwania udanym biegiem można pomylić, że jego program jest poprawny.
silviot

Odpowiedzi:


10

APL (Dyalog) ( 44 43 39 34)

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

Wyjaśnienie:

  • 2 11⍴'Hello World',⍳11 tworzy macierz: (H, 1), (e, 2), ...
  • &⌿ oznacza: dla każdej kolumny macierzy wykonaj w osobnym wątku:
  • W wątku jest teraz postacią i nadszedł czas
  • ⎕DL⊃⍵czeka sekund.
  • Następnie ⍞←⍺wypisuje postać.

11
Wiesz co? Uwierzę ci na słowo ... :)
Bolster

OK, to jest najkrótsze. Gratulacje!
Tharwen

19

C, 61 62 znaków

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

Wszystkie funkcje biblioteki pthread mają długie nazwy, więc zamiast tego uruchomiłem osobny proces dla każdej postaci. fork()jest o wiele krótszy.

Konieczne było użycie write()zamiast, putchar()ponieważ funkcje buforowania stdio nie są bezpieczne dla wątków.

Edytowano : Wykonaj kopię zapasową do 62 znaków. W mojej gorliwości zejście do 61 znaków obniżyło także bezpieczeństwo wątków.


Powinna istnieć możliwość zmiany instrukcji write na write(1,"Hello World\n",!!++i)na 2 bajty. W przeciwnym razie fajne rozwiązanie.
primo

Powinieneś spróbować i zobaczyć, co to wytwarza.
breadbox

Mój błąd miał na myśli!!++i
primo

To wydaje się być tym, co napisałeś za pierwszym razem, więc nie rozumiem, jaki błąd próbowałeś poprawić. I nie byłem żartobliwy: szczerze mówiąc miałem na myśli, że powinieneś spróbować sam i zobaczyć, co się stanie. Po usunięciu dodatku każdy wątek wydrukuje tylko pierwszy znak ciągu.
breadbox

Pierwotnie napisałem !!i++, ale zredagowałem go kilka sekund później, ponieważ zdałem sobie sprawę, że 0przy pierwszej iteracji będzie to oceniać . Zakładałem, że widziałeś niezredagowaną wersję. Nie jestem w stanie przetestować twojego kodu, ponieważ wypisuje on tylko pierwszy znak, raz . Istnieje jednak wiele alternatyw; i++<13, używając !!i, a nawetwrite(1,"Hello World\n",i++>13||fork()||main())
primo

9

Ruby, 46 znaków

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

Jest zsynchronizowany ze względu na fakt, że program czeka na zakończenie wątku przed rozpoczęciem następnego wątku i kontynuowaniem następnego znaku.


7

Pythonect (35 znaków)

http://www.pythonect.org

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

To najkrótszy jak dotąd. Ponieważ nie mam pojęcia, co to właściwie robi, założę, że jest poprawne i zaakceptuję to za dzień lub dwa, jeśli nikt nie wypowie się przeciwko temu lub opublikuje coś krótszego.
Tharwen

1
Właśnie obejrzałem przykłady. Czy instrukcja drukowana lub lista nie powinna zawierać nawiasów []?
Dalin Seivewright

1
Cześć, przesyłam odpowiedź Itzika (twórcy pythonecta): „->” i „|” są operatorami Pythonect. Operator potoku przekazuje po jednym elemencie, a drugi przesyła wszystkie elementy jednocześnie. Powyższy program zajmuje ciąg „Hello World”, przekształca go w listę, dzieli listę na znaki i wysyła każdy znak do wydrukowania. Możliwe jest dalsze optymalizowanie programu, do: iter („Hello World”) | print To, co robi, iteruje ciąg „Hello World” i wysyła każdy znak do wydrukowania (w sposób synchronizujący / blokujący). Pozdrawiam, Itzik Kotler | ikotler.org
Leon Fedotov

jak odbywa się tutaj gwintowanie ???
Rohit

1
Jak wspomniano @LeonFedotov i ze źródła pythonect (dostępnego w pythonect ) po analizie , dla każdej iteracji i operatora '->' wątki są wykonywane w następujący sposób: thread = threading.Thread (target = __ run, args = ([( operator, element)] + wyrażenie [1:], copy.copy (globals_), copy.copy (locals_), return_value_queue, nie iteruj_literal_arrays)) thread.start ()
Jonathan Rom

6

Python ( 101 93 98)

To jest rozwiązanie Petera Taylora. Działa poprzez opóźnienie drukowania N-tego znaku o N sekund. Zobacz komentarze.

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

To jest oryginalny:

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

Działało, ponieważ czas potrzebny do wydrukowania pojedynczego znaku jest krótszy niż czas potrzebny Pythonowi na zainicjowanie nowego wątku, dlatego N-ty wątek skończyłby się przed utworzeniem N + 1-tego wątku. Najwyraźniej poleganie na tym jest niezgodne z zasadami.


Możesz zapisać 3 znaki, zmieniając import sys,threadingna import sys,threading as ti możesz zaoszczędzić 2, przekazując argumenty do wątku jako argumenty pozycyjne zamiast argumentów słów kluczowych.
Joel Cornett

2
Gdzie jest kod dotyczący bezpieczeństwa wątków? Po prostu strzelasz do wątków, mając nadzieję, że będą działały w tej samej kolejności, w jakiej je uruchomisz. Nie zawsze będzie to prawdą i jest w rzeczywistości „trudną częścią” tego problemu. Zamiast optymalizować rozmiar programu, powinieneś ponownie rozważyć problem: nie dostałeś go w pierwszej kolejności. Zobacz gist.github.com/2761278, aby uzyskać dowód, że ten kod nie działa.
silviot

Szybka naprawa. Użyj threading.Timerzamiast threading.Thread. Podaj xjako parametr uśpienia.
Joel Cornett

1
Sugestię Joela można poprawić o 4 dofor x in range(11):t.Timer(x,sys.stdout.write,"Hello World"[x]).start()
Peter Taylor

1
@silviot: Wykorzystałem fakt, że tworzenie wątków wiąże się z tworzeniem instancji obiektu, a tym samym trwa od jednej do dwóch trzecich milisekundy w testowanych systemach. Wyjście postaci nie ma tego narzutu, zajmuje tylko jedną dziesiątą tego czasu. Dlatego „zawsze” będzie działać, o ile niczego nie przesłonisz. Stdout jest buforowany, więc nie powinno to nigdy powodować problemów.
marinus

4

C # 73

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

nie jestem pewien, czy spełnia to wymóg, aby każda litera była drukowana za pomocą własnego wątku, ponieważ tpl może ponownie używać wątków.
statichippo

Teoretycznie masz rację, ale na moim komputerze ThreadPool.GetMaxThreads lub ThreadPool.GetAvailableThreads zwraca wartość około 1000 zarówno dla wątków IO, jak i wątków roboczych.
JJoos,

4

APL (Dyalog Unicode) , 28 bajtów SBCS

Pełny program Drukuje na stderr. Zainspirowany rozwiązaniem marinus .

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

Wypróbuj online!

⍳11 pierwsze 11 liczb całkowitych

'Hello World'{}&¨ Dla każdej liczby całkowitej jako prawego argumentu ( ), spawn następującą funkcję z odpowiednim znakiem jako lewym argumentem ( ):

⎕DL⍵d e l Ay sek prawego argumentu

⍺⊣ odrzuć to (skuteczne opóźnienie) na korzyść znaku lewostronnego

⍞← wydrukuj to na standardowe wyjście bez przerywania linii


jak o ⍞∘←&¨'dlroW olleH'? - Nie wiem, czy jest to teoretycznie gwarantowane, ale wydaje się, że zawsze drukuje je we właściwej kolejności
ngn

@ngn Oczywiście, ponieważ nie ma gwarancji, że wątki będą działały w kolejności, w jakiej je uruchomiłeś, musisz zabezpieczyć swój wątek programu, aby upewnić się, że wydruk zostanie wydrukowany we właściwej kolejności.
Adám

to ograniczenie, które próbowałem rozwiązać, może być zagwarantowane. Uruchomiłem to 100 razy i wygląda na to, że harmonogram wątków zawsze pobiera wątki w odwrotnej kolejności. A przynajmniej tak jest, gdy jest ≤11 zadań. AFAIK ⍞∘←nie jest przerywany (a może jest to możliwe? Może poprosić programistę języka C?). Dyalog implementuje zielone wątki - 1 prawdziwy wątek udaje, że jest ich wiele, więc jeśli nie może wystąpić (zielony) przełącznik wątku, kolejność jest przewidywalna.
ngn

3

Java (160 znaków)

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

Tak, wiem, że to zły język dla golfa kodowego, robię to dla zabawy.


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 znaków
Prince John Wesley

@Prince Yep, dzięki za korektę!
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 znaków
Wouter Coekaerts

@Wouter Bardzo dobry! Całkowicie za tym tęskniłem.
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 znaków
Prince John Wesley

2

Bash (64)

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

@marinus Grał w golfa przez 3 znaki::()([ "$1" ]&&(printf "${1:0:1}"&: "${1:1}"));: Hello\ World
Cyfrowa trauma

@fossilet Działa dla mnie zarówno w systemie Linux, jak i OSX, w kilku wersjach bash. Ostatni lub dwa znaki są czasami drukowane po zachęcie powłoki.
Cyfrowa 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

Nie jestem pewien, czy pomnożyć przez 9999 - mam Xeon 2Ghz, na którym będzie działał dobrze, nawet jeśli nie, ale mam też Pentium 4, który tego potrzebuje (999 dał zniekształcony wynik, a 99 nie zrobił ” w ogóle nic.)


Zapisz 2 znaki, używając (*5^6)zamiast (*9999)i nie używając cudzysłowów dla mapM_.
Ślimak mechaniczny

@Mechanicalsnail Jeśli usuniesz tyły, potrzebujesz dodatkowej pary nawiasów klamrowych, w przeciwnym razie będzie to analizowane jako (((mapM_ (\(x,y) ... )) zip) [0..]) ... którego nie chcesz.
marinus

Co do tego 999, może być obcinany do 0 z powodu ograniczeń systemu operacyjnego, ale mogę się mylić. Z jakiego systemu operacyjnego korzystasz?
Joey Adams



1

D (135 znaków)

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

Następny wątek zaczynam dopiero, gdy już wydrukowałem bieżący znak

edytuj +2 znaki, aby lepiej sprawdzić wiązanie


Dostaję core.exception.RangeError@test.d(6): Range violationbłąd.
Fish Monitor

@fossilet I fix it
maniak ratchet

1

Scala 74

"Hello World".zipWithIndex.par.map(x=>{Thread.sleep(x._2*99);print(x._1)})
  • zipWithIndex produkuje ((H, 0), (e, 1), (1, 2) ...).
  • par sprawia, że ​​jest to kolekcja równoległa.

Testy:

(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- Rozumiem
Książę John Wesley

println(Thread.currentThread.getName)Pokazuje również , że wątki nie są unikalne.
Prince John Wesley,

@PrinceJohnWesley: Myślę, że potrzebujesz jednego rdzenia na literę, aby par rozdzielił pracę na wszystkie rdzenie.
użytkownik nieznany

Mam to. więc wymagany jest jeden rdzeń na literę + wysoka rozdzielczość zegara systemowego.
Prince John Wesley,

użyj mapzamiast foreach. możesz zapisać 4 znaki.
Prince John Wesley,

1

JavaScript (72)

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

1

scala (45)

Rozwiązanie oparte na łączeniu wątków

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

lub

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

1

To jest moja próba F #. Mój pierwszy poważny program w języku F #. Proszę bądź uprzejmy.

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


0

Erlang (90)

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

Skompilować erlc +export_all h.erl



0

Python: za dużo znaków, ale działa.

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

Nie rozumiem, jaki jest cel losowania czasu snu.
Joel Cornett

@Joel, aby upewnić się, że kiedy to działa, nie jest to szczęśliwy przypadek, że wątki są wykonywane w tej samej kolejności, w jakiej zostały zwolnione.
silviot


0

Cel C (183 znaków)

-(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 znaków

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

Jak to działa, każdy wątek zaczyna się od następnego po wyświetleniu swojego charakteru, więc tak naprawdę przydatne rzeczy nie mogą wydarzyć się poza sekwencją.


0

Bash , 43 bajty

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

Wypróbuj online!

xargsrozwidla osobny printfproces dla każdej postaci (i czeka na zakończenie).

Bash , 45 bajtów, brak zewnętrznych narzędzi

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

Wypróbuj online!

Rozwija się (printf H); (printf e); (printf l); (printf l); (printf o); (printf \ ); (printf W); (printf o); (printf r); (printf l); (printf d);przed oceną. Nawiasy sprawiają, że rozwidlenie Bash jest podpowłoką dla każdej litery (i czeka na zakończenie), ale tym razem printfjest to wbudowane Bash.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.