HelolW rdlo (스레딩 도전)


39

나는 당신에게 도전이 있습니다 :

  • 모든 언어를 사용하여 "Hello World"를 인쇄하십시오.
  • 각 문자는 고유 한 고유 스레드에서 인쇄해야합니다

그게 다야. 스레드가 시작 순서대로 작동한다는 보장이 없으므로 출력이 올바른 순서로 인쇄되도록 프로그램 스레드를 안전하게 만들어야합니다.

그리고 이것이 코드 골프이기 때문에 가장 짧은 프로그램이 승리합니다.

최신 정보:

우승자는 34자인 Marinus의 APL 출품작 입니다. 또한 가장 읽기 어려운 항목으로 선정되었습니다.


10
이에 대한 더 좋은 이름은 다음과 같습니다.HelolW rdlo
Cristian Lupascu

하, 나도 좋아 바로 변경 : D
Tharwen

Aww ... 너무 짧아요
Tharwen

1
얼마나 많은 사람들이 "쓰레드가 시작한 순서대로 작동한다는 보장이 없기 때문에"힌트를 무시하고 그들이 올바른 것으로 생각한다고 생각하는 것은 재미있다.
Joa Ebert

"실이 시작 순서대로 작동한다는 보장은 없다"는 것이 사실이지만, 실제로는 항상 그런 사소한 프로그램에 대해 거의 수행 할 것입니다. 이 혼란을 피하기 위해 각 스레드 1) (작은) 임의의 수의 밀리 초를 기다립니다 .2) char을 출력합니다 .3) 다른 임의의 (아마도) 시간을 기다립니다. 코드는 몇 번만 실행하면 작동합니다. 그리고 join () 솔루션은 훨씬 나빠질 것입니다. 무작위 대기 없이는 자신의 프로그램이 정확하다고 생각하는 성공적인 실행으로 오도 될 수 있습니다.
silviot

답변:


10

APL (Dyalog) ( 44 43 39 34)

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

설명:

  • 2 11⍴'Hello World',⍳11 행렬을 생성합니다 : (H, 1), (e, 2), ...
  • &⌿ 의미 : 행렬의 각 열에 대해 별도의 스레드에서 수행하십시오.
  • 스레드에서, 이제 캐릭터가되고 이제 시간입니다
  • ⎕DL⊃⍵몇 초 동안 기다립니다 .
  • 그런 다음 ⍞←⍺문자를 출력합니다.

11
그거 알아? 나는 당신의 말을하겠습니다 ... :)
Bolster 9:20에

좋습니다, 이것이 가장 짧습니다. 축하합니다!
Tharwen

19

C, 61 62 자

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

pthread 라이브러리 함수는 모두 loooooong 이름을 가지므로 대신 각 문자에 대해 별도의 전체 프로세스를 시작했습니다. fork()너무 짧아요

stdio 버퍼링 기능은 스레드로부터 안전하지 않기 때문에 write()대신 사용해야 했습니다 putchar().

편집 : 최대 62 자까지 백업합니다. 내 열심에서 61 자로 떨어 뜨려도 스레드 안전성이 떨어졌습니다.


쓰기 명령문을 write(1,"Hello World\n",!!++i)2 바이트 로 변경할 수 있어야합니다 . 그렇지 않으면 좋은 해결책입니다.
primo

당신은 그것을 시도하고 그것이 생산하는 것을 참조해야합니다.
breadbox

내 실수는, !!++i
프리모

그것은 당신이 처음으로 쓴 것으로 보이므로, 당신이 어떤 실수를 고치려고했는지 모르겠습니다. 그리고 나는 정직하지 않았습니다. 솔직히 당신이 직접 시도해보고 무슨 일이 일어나는지보아야한다는 것을 의미했습니다. 추가를 제거하면 모든 스레드가 문자열의 첫 문자 만 인쇄합니다.
breadbox

나는 원래 썼지 !!i++만 몇 초 후에 편집했다. 왜냐하면 0첫 번째 반복에서 평가 될 것이라는 것을 깨달았 기 때문이다 . 편집하지 않은 버전을 본 것으로 가정합니다. 첫 번째 문자 만 한 번만 인쇄하기 때문에 코드를 테스트 할 수 없습니다 . 그러나 많은 대안이 있습니다. i++<13, !!i또는 심지어write(1,"Hello World\n",i++>13||fork()||main())
primo를

9

루비, 46 자

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

프로그램은 다음 스레드를 시작하고 다음 문자를 계속하기 전에 스레드가 종료 될 때까지 대기하기 때문에 동기화됩니다.


7

Pythonect (35 자)

http://www.pythonect.org

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

지금까지 가장 짧습니다. 나는 그것이 실제로 무엇을하는지 알지 못하기 때문에, 아무도 그것에 대해 말하거나 더 짧은 것을 게시하지 않으면 올바른 것으로 간주하고 하루나 이틀 안에 그것을 받아 들일 것입니다.
Tharwen

1
예제를 간단히 살펴 보았습니다. 문장이나리스트 문장에 괄호 []가 붙어 있지 않아야합니까?
Dalin Seivewright

1
안녕하세요, Itzik (pythonect의 작성자) 답변 전달 : '->'및 '|' 둘 다 Pythonect 연산자입니다. 파이프 연산자는 한 항목에서 한 항목을 전달하고 다른 연산자는 모든 항목을 한 번에 전달합니다. 위의 프로그램은 "Hello World"문자열을 가져 와서 목록으로 바꾸고 목록을 문자로 나누고 각 문자를 보내서 인쇄합니다. 다음과 같이 프로그램을 더욱 최적화 할 수 있습니다. iter ( "Hello World") | print "Hello World"문자열을 반복하고 인쇄 할 각 문자를 동기화 / 차단 방식으로 보냅니다. 감사합니다, Itzik Kotler | ikotler.org
Leon Fedotov

스레딩은 어떻게 수행됩니까 ???
Rohit

1
@LeonFedotov가 언급했듯이 파싱 ​​후 pythonect 소스 ( pythonect 에서 사용 가능)에서 각 반복 및 '->'연산자에 대해 스레딩은 다음과 같이 수행됩니다. thread = threading.Thread (target = __ run, args = ([( operator, item)] + expression [1 :], copy.copy (globals_), copy.copy (locals_), return_value_queue, iterate_literal_arrays가 아님)) thread.start ()
Jonathan Rom

6

파이썬 ( 101 93 98)

이것이 Peter Taylor의 솔루션입니다. N 번째 문자 인쇄를 N 초 지연시켜 작동합니다. 의견을 참조하십시오.

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

이것은 원래 것입니다 :

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

단일 문자를 인쇄하는 데 걸리는 시간이 Python이 새 스레드를 초기화하는 데 걸리는 시간보다 짧기 때문에 N + 1 스레드가 생성되기 전에 N 번째 스레드가 완료되기 때문에 작동했습니다. 분명히 이것에 의존하는 규칙에 위배됩니다.


당신은 변경하여 3 개 문자를 저장할 수 import sys,threadingimport sys,threading as t당신은 오히려 키워드 인자보다, 위치 인수로 스레드에 인수를 전달하여, 더 2를 저장할 수 있습니다.
Joel Cornett

2
스레드 안전을 다루는 코드는 어디에 있습니까? 스레드는 시작하는 순서와 동일하게 실행되기를 바랍니다. 이것은 항상 사실이 아니며 실제로이 문제의 "어려운 부분"입니다. 프로그램 크기를 최적화하는 대신 문제를 다시 고려해야합니다. 처음에는 얻지 못했습니다. 이 코드가 작동하지 않는다는 증거는 gist.github.com/2761278 을 참조하십시오 .
silviot

빠른 수정. threading.Timer대신에 사용하십시오 threading.Thread. 에서 통과 x슬립 매개 변수로.
Joel Cornett

1
Joel for x in range(11):t.Timer(x,sys.stdout.write,"Hello World"[x]).start()
Taylor

1
@ silviot : 스레드 생성에는 객체 인스턴스화가 포함되므로 테스트 한 시스템에서 1 ~ 3 분의 1 밀리 초가 걸립니다. 문자 출력에는이 오버 헤드가 없으며이 시간의 10 분의 1 만 걸립니다. 따라서 아무것도 무시하지 않는 한 "항상"작동합니다. Stdout은 버퍼링되므로 문제가 발생하지 않습니다.
marinus

4

C # 73

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

tpl은 스레드를 재사용 할 수 있으므로 각 문자를 자체 스레드를 통해 인쇄해야한다는 요구 사항을 충족하지는 않습니다.
statichippo

이론적으로는 맞지만 내 PC에서 ThreadPool.GetMaxThreads 또는 ThreadPool.GetAvailableThreads는 IO 및 작업자 스레드 모두에 대해 약 1000의 값을 반환합니다.
JJoos

4

APL (Dyalog Unicode) , 28 바이트 SBCS

전체 프로그램. stderr에 인쇄합니다. marinus의 솔루션에서 영감을 얻었습니다 .

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

온라인으로 사용해보십시오!

⍳11 처음 11 개의 정수

'Hello World'{}&¨ 오른쪽 인수 ( ) 로 각 정수에 대해 해당 문자를 왼쪽 인수 ( ) 로 사용하여 다음 함수를 생성합니다 .

⎕DL⍵D의리터 AY 오른쪽 인수 초

⍺⊣ 왼쪽 인수 특성에 찬성하여 (유효 지연) 버립니다

⍞← 줄 바꿈없이 stdout에 인쇄


방법은 ⍞∘←&¨'dlroW olleH'? -이론적으로 보장되는지는 모르겠지만 항상 올바른 순서로 인쇄하는 것 같습니다.
ngn

@ngn 분명히, 스레드가 시작 순서대로 작동한다는 보장이 없으므로 출력이 올바른 순서로 인쇄되도록 프로그램 스레드를 안전하게 만들어야합니다.
Adám

그것이 내가 해결하려는 제약 사항입니다. 나는 이것을 100 번 실행했으며 스레드 스케줄러가 항상 스레드를 역순으로 선택하는 것처럼 보입니다. 또는 적어도 ≤11 작업이있는 경우입니다. AFAIK ⍞∘←는 방해받지 않습니다 (또는 C 개발자에게 물어볼 수 있습니까?). Dyalog는 녹색 스레드를 구현합니다. 1 실제 스레드는 많은 척을하기 때문에 (녹색) 스레드 전환이 발생하지 않으면 순서 예측할 수 있습니다.
ngn

3

자바 (160 자)

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

그래, 나는 이것이 코드 골프에 대해 잘못된 언어라는 것을 알고있다.


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 자
존 웨슬리 왕자

@ 프린스 그래, 정정 주셔서 감사합니다!
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 문자
Wouter Coekaerts

@Wouter 아주 좋은 것! 나는 그것을 완전히 놓쳤다.
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 자
John Wesley 왕자

2

배쉬 (64)

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

@marinus 골프는 3 개의 문자에 의해 행해진 다 ::()([ "$1" ]&&(printf "${1:0:1}"&: "${1:1}"));: Hello\ World
Digital Trauma

@fossilet Linux와 OSX 모두에서 여러 bash 버전에서 작동합니다. 쉘 프롬프트 후에 마지막 한두 문자가 인쇄되는 경우가 있습니다.
디지털 외상

2

하스켈 ( 120 118)

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

나는 9999를 곱한 것이 확실하지 않습니다-2Ghz Xeon이 있어도 잘 작동하지만 Pentium 4가 필요합니다. 아무것도하지 마십시오.)


에 대해 인용 부호를 사용하지 (*5^6)않고 대신 사용하여 2자를 저장하십시오 . (*9999)mapM_
기계 달팽이

@Mechanicalsnail 백틱을 제거하면 추가 괄호 쌍이 필요합니다. 그렇지 않으면 (((mapM_ (\(x,y) ... )) zip) [0..]) ...원하지 않는 구문으로 구문 분석됩니다 .
marinus

에 관해서는 999운영 체제 제한으로 인해 0으로 잘릴 수 있지만 잘못되었을 수 있습니다. 어떤 OS를 사용하고 있습니까?
Joey Adams



1

D (135 자)

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

현재 문자를 이미 인쇄했을 때 다음 스레드 만 시작합니다.

더 나은 바운드 검사를 위해 +2 문자 편집


내가 얻을 core.exception.RangeError@test.d(6): Range violation오류입니다.
물고기 모니터

@ fossilet 내가 고쳐
래칫 괴물

1

스칼라 74

"Hello World".zipWithIndex.par.map(x=>{Thread.sleep(x._2*99);print(x._1)})
  • zipWithIndex는 ((H, 0), (e, 1), (l, 2) ...)를 생성합니다.
  • par는 그것을 병렬 컬렉션으로 만듭니다.

테스트 :

(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-나는 이것을 얻었다
프린스 존 웨슬리

또한 println(Thread.currentThread.getName)스레드가 고유하지 않음을 보여줍니다.
프린스 존 웨슬리

@ 프린스 존 웨슬리 (PrinceJohnWesley) : 편지 당 하나의 코어가 필요하다고 생각하므로 파는 모든 코어에 작업을 배포합니다.
사용자가 알 수 없음

알았어 따라서 문자 당 하나의 코어 + 시스템 시계의 높은 해상도가 필요합니다.
프린스 존 웨슬리

map대신에 사용하십시오 foreach. 당신은 4 문자를 저장할 수 있습니다.
프린스 존 웨슬리

1

자바 스크립트 (72)

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

1

스칼라 (45)

스레드 # 조인 기반 솔루션

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

또는

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

1

이것은 나의 F # 시도입니다. 나의 첫번째 심각한 F # 프로그램. 친절하세요.

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

0

가다

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

당신은 문자를 세지 않아도됩니다-우리는 당신을 위해 그렇게 할 것입니다!
사용자가 알 수 없음

0

에를 랑 (90)

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

엮다 erlc +export_all h.erl



0

파이썬 : 문자가 너무 많지만 작동합니다.

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

수면 시간을 무작위로 나누는 목적이 무엇인지 이해하지 못합니다.
Joel Cornett

@Joel은 작동 할 때 스레드가 해고 된 순서와 동일한 순서로 실행되는 운이 우연의 일치가 아닌지 확인합니다.
silviot


0

Objective-C (183 자)

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

하스켈 99 자

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

작동 방식은 각 스레드가 문자를 표시 한 후 다음에 시작되므로 실제로 유용한 항목은 순서가 맞지 않을 수 없습니다.


0

배쉬 , 43 바이트

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

온라인으로 사용해보십시오!

xargsprintf각 문자에 대해 별도의 프로세스를 분기하고 종료 될 때까지 기다립니다.

Bash , 45 바이트, 외부 유틸리티 없음

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

온라인으로 사용해보십시오!

(printf H); (printf e); (printf l); (printf l); (printf o); (printf \ ); (printf W); (printf o); (printf r); (printf l); (printf d);평가 전으로 확장합니다 . 괄호는 Bash 포크를 각 문자의 서브 쉘로 만들고 종료 될 때까지 기다리지 만 이번에 printf는 Bash가 내장되어 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.