HelolW rdlo(スレッド化の課題)


39

私はあなたのために挑戦しています:

  • 任意の言語を使用して「Hello World」を印刷します。
  • 各文字は、独自の一意のスレッドから印刷する必要があります

それでおしまい。明らかに、スレッドが起動した順序で動作するという保証はないため、プログラムをスレッドセーフにして、出力が正しい順序で出力されるようにする必要があります。

そして、これはコードゴルフであるため、最短のプログラムが勝利します。

更新:

勝者は34文字のMarinusのAPLエントリです。また、最も読みにくいエントリで賞を獲得します。


10
このため、より良い名前があったであろうHelolW rdlo
クリスティアンLupascu

ハ、私はそれが好きです。すぐにそれを変更します
。D–ターウェン

ああ

1
「明らかに、スレッドが開始した順序でスレッドが動作するという保証はないので」というヒントを無視して、正しいと思う人がどれだけいるかを見るのは面白いです。
ジョアエバート

実際には、「スレッドが起動した順序でスレッドが動作するという保証はありません」というのは事実ですが、実際には、このような些細なプログラムに対してほとんど常に実行します。この混乱を避けるために、各スレッド 1)(小さな)ミリ秒の乱数を待つ2)文字を出力する3)別のランダムな(おそらく長い)時間を待つ必要があるという問題に追加します。コードは数回実行するだけで機能します。また、join()ソリューションのパフォーマンスはさらに低下します。ランダムに待機しないと、実行が成功して、自分のプログラムが正しいと思うように誤解される場合があります。
silviot

回答:


10

APL(ダイアログ)(44 43 39 34)

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

説明:

  • 2 11⍴'Hello World',⍳11 行列を作成します:(H、1)、(e、2)、...
  • &⌿ 意味:マトリックスの列ごとに、個別のスレッドで実行します。
  • スレッドでは、今のキャラクターであり、今の時間です
  • ⎕DL⊃⍵秒待ちます。
  • 次に、⍞←⍺文字を出力します。

11
あのね?私はあなたの言葉を受け取ります... :)
ボルスター

OK、これが最短です。おめでとうございます!
-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バイトに変更することができるはずです。それ以外の場合の素晴らしい解決策。
プリモ

あなたはそれを試して、それが生成するものを見るべきです。
ブレッドボックス

私の間違いは、私が意味するもの!!++i
プリモ

それはあなたが最初に書いたものであるように見えるので、あなたが修正しようとしていた間違いはわかりません。そして、私は面白くはありませんでした。正直に言って、自分で試してみて、何が起こるか見てみるべきだということです。追加を削除することにより、すべてのスレッドは文字列の最初の文字を出力します。
ブレッドボックス

私はもともとを書いてい!!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

これはこれまでで最短です。私はそれが実際に何をするのかわからないので、それが正しいと仮定し、誰もそれに対して発言したり、何か短いものを投稿したりしない場合は、1、2日でそれを受け入れます。
サーウェン

1
例を簡単に見てみました。ステートメントまたはリストステートメントを印刷する必要がありますか?
ダリンセイヴライト

1
こんにちは、Itzik(pythonectの作成者)の回答を転送しています: '->'および '|' どちらもPythonect演算子です。パイプオペレーターは1つのアイテムを1つのアイテムに渡し、もう1つのオペレーターはすべてのアイテムを一度に渡します。上記のプログラムが行うことは、「Hello World」文字列を受け取り、それをリストに変換し、リストを文字に分割し、各文字を印刷に送信します。次のように、プログラムをさらに最適化することが可能です。iter( "Hello World")| printは、「Hello World」文字列を反復処理し、各文字を(同期/ブロック方式で)印刷するために送信します。よろしく、Itzik Kotler | ikotler.org
レオンFedotov

ここでスレッドはどのように行われますか?
ローヒット

1
等@LeonFedotovが挙げられ、(で利用可能pythonect源からpythonect各反復とのために、解析後)「 - >」演算子、スレッドは次のように行われる:スレッド= threading.Thread(目標= __ラン、引数=([( operator、item)] + expression [1:]、copy.copy(globals_)、copy.copy(locals_)、return_value_queue、not iterate_literal_arrays))thread.start()
ジョナサンロム

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番目のスレッドはN + 1番目のスレッドが作成される前に終了します。明らかにこれに依存することはルールに反しています。


あなたは、変更することで、3つの文字を保存することができますimport sys,threadingimport sys,threading as t、あなたは、位置引数ではなくキーワード引数としてスレッドに引数を渡すことによって、より多くの2を保存することができます。
ジョエルコーネット

2
スレッドセーフを扱うコードはどこにありますか?スレッドを起動するのと同じ順序で実行されることを期待してスレッドを起動します。これは常に真実とは限らず、実際にはこの問題の「難しい部分」です。プログラムのサイズを最適化する代わりに、問題を再考する必要があります。そもそも問題が発生していません。このコードが機能しないという証拠については、gist.github.com / 2761278を参照してください。
silviot

クイックフィックス。のthreading.Timer代わりに使用しますthreading.Threadxスリープパラメータとして渡します。
ジョエルコーネット

1
ジョエルの提案は4に改善できますfor x in range(11):t.Timer(x,sys.stdout.write,"Hello World"[x]).start()
ピーターテイラー

1
@silviot:スレッドの作成にはオブジェクトのインスタンス化が含まれるため、テストしたシステムでは1〜3分の2ミリ秒かかるという事実を利用していました。文字出力にはこのオーバーヘッドがなく、この時間の10分の1しかかかりません。したがって、何もオーバーライドしない限り、「常に」機能します。Stdoutはバッファリングされるため、問題が発生することはありません。
マリヌス

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に出力します。マリナスのソリューションに触発されました。

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

オンラインでお試しください!

⍳11 最初の11個の整数

'Hello World'{}&¨ 右引数()としての各整数に対して、左引数()として対応する文字を使用して次の関数を生成します。

⎕DL⍵d e l ay右引数の秒

⍺⊣ 左引数の文字を優先してそれを破棄します(有効な遅延)

⍞← 改行なしで標準出力に出力します


どう⍞∘←&¨'dlroW olleH'?-理論的に保証されているかどうかはわかりませんが、常に正しい順序で印刷するようです
-ngn

@ngn 明らかに、スレッドが起動した順序で動作するという保証はないため、プログラムをスレッドセーフにして、出力が正しい順序で出力されるようにする必要があります。
アダム

それが私が対処しようとしていた制約であり、保証されるかもしれません。これを100回実行しましたが、スレッドスケジューラは常に逆の順序でスレッドを取得するようです。または、少なくとも11個以下のタスクがある場合はそうです。AFAIK ⍞∘←は中断できません(または、C開発者に尋ねることができますか?)。Dyalogはグリーンスレッドを実装します-多くのふりをした1つの実際のスレッドなので、(グリーン)スレッドの切り替えが発生しない場合、順序予測可能です。
ngn

3

Java(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文字
プリンスジョンウェスリー

@プリンスうん、修正してくれてありがとう!
マルコム

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非常に良いものです!私はそれを見逃した。
マルコム

1
@ Malcolm、@ bkil、@ Wouter:-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();}}文字
ジョンウェスリー王子

2

バッシュ(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
デジタルトラウマ14年

@fossiletは、LinuxとOSXの両方で、いくつかのbashバージョンで動作します。シェルプロンプトの後に、最後の1文字または2文字が印刷される場合があります。
デジタル外傷14年

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もあります(999は文字化けし、99は出力しませんでした) tは何もしません。)


の逆引用符を使用し、使用しない(*5^6)で2文字を保存します。(*9999)mapM_
機械式カタツムリ

@Mechanicalsnailバックティックを削除する場合は、追加のブレースペアが必要(((mapM_ (\(x,y) ... )) zip) [0..]) ...です。それ以外の場合は、不要なものとして解析されます。
マリヌス

については999、オペレーティングシステムの制限により0に切り捨てられる場合がありますが、間違っている可能性があります。どのOSを使用していますか?
ジョーイアダムス



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:文字ごとに1つのコアが必要だと思うので、パーはすべてのコアに作業を分散します。
ユーザー不明

わかった。そのため、文字ごとに1コア+システムクロックの高解像度が必要です。
ジョンウェスリー王子

map代わりに使用しますforeach。4文字を保存できます。
ジョン・ウェスリー王子

1

Javascript(72)

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


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

Python:文字が多すぎますが、機能します。

# 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は、動作するときに、スレッドが起動されたのと同じ順序で実行されるという偶然の偶然ではないことを保証します。
silviot

0

C#90 84

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

実行中のバージョン:http : //ideone.com/0dXNw


console.writeは非常に高速であるため、これはあなたにとってうまくいくかもしれませんが、スレッドセーフではありません!
statichippo

@statichippoあなたは正しいです。私はそれを修正しました。
クリスチャンルパスク

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

Haskell 99キャラクター

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

どのように機能するかは、各スレッドがその文字を表示した後に次のスレッドを開始するため、実際に有用なことは順不同で発生することはありません。


0

Bash、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.