HelolW rdlo (Tantangan threading)

39

Saya punya tantangan untuk Anda:

  • Cetak "Hello World" menggunakan bahasa apa pun.
  • Setiap karakter harus dicetak dari utasnya sendiri yang unik

Itu dia. Jelas, karena tidak ada jaminan bahwa utas akan beroperasi sesuai urutan Anda memulainya, Anda harus membuat utas program Anda aman untuk memastikan hasil cetak dalam urutan yang benar.

Dan, karena ini golf kode, program terpendek menang.

Memperbarui:

Pemenangnya adalah entri APL Marinus , dengan 34 karakter. Itu juga memenangkan hadiah untuk entri yang paling mudah dibaca.

Tharwen
sumber
10
Nama yang lebih baik untuk ini adalahHelolW rdlo
Cristian Lupascu
Ha, saya suka itu. Mengubahnya segera: D
Tharwen
Ah ... terlalu pendek
Tharwen
1
Sangat lucu untuk melihat berapa banyak orang mengabaikan "jelas, karena tidak ada jaminan bahwa utas akan beroperasi dalam urutan Anda memulai mereka" petunjuk dan berpikir mereka melakukannya dengan benar.
Joa Ebert
Meskipun memang benar bahwa "tidak ada jaminan bahwa utas akan beroperasi sesuai urutan Anda memulainya" dalam praktiknya hampir selalu akan dilakukan untuk program sepele seperti itu. Untuk menghindari kebingungan ini, saya akan menambahkan ke masalah bahwa setiap utas harus 1) menunggu jumlah milidetik acak (kecil) 2) menghasilkan karakternya 3) menunggu waktu acak lain (mungkin lama) Dengan cara ini orang dapat mengetahui apakah kode berfungsi dengan hanya menjalankannya beberapa kali. Dan solusi join () akan berkinerja lebih buruk. Tanpa menunggu secara acak, orang dapat tersesat oleh jalan yang berhasil untuk berpikir bahwa programnya benar.
silviot

Jawaban:

10

APL (Dyalog) ( 44 43 39 34)

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

Penjelasan:

  • 2 11⍴'Hello World',⍳11 membuat matriks: (H, 1), (e, 2), ...
  • &⌿ berarti: untuk setiap kolom matriks, lakukan pada utas terpisah:
  • Di utas, sekarang karakter dan sekarang waktunya
  • ⎕DL⊃⍵menunggu sebentar.
  • Kemudian, ⍞←⍺menampilkan karakter.
marinus
sumber
11
Kamu tahu apa? Saya akan mengambil kata-kata Anda untuk itu ... :)
Guling
OKE, ini yang terpendek. Selamat!
Tharwen
19

C, 61 62 karakter

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

Fungsi pthread library semuanya memiliki nama loooooong, jadi alih-alih saya menjalankan seluruh proses terpisah untuk setiap karakter. fork()jauh lebih pendek.

Itu perlu digunakan write()daripada putchar()karena fungsi buffer stdio tidak aman-thread.

Diedit : Cadangkan hingga 62 karakter. Dalam semangat saya, menjatuhkan ke 61 karakter juga menjatuhkan keamanan benang.

kotak roti
sumber
Seharusnya dimungkinkan untuk mengubah pernyataan tulis menjadi write(1,"Hello World\n",!!++i)2 byte. Solusi bagus jika tidak.
Primo
Anda harus mencobanya dan melihat apa yang dihasilkannya.
kotak roti
Kesalahan saya, maksud saya!!++i
primo
Tampaknya itu yang Anda tulis pertama kali, jadi saya tidak melihat kesalahan apa yang Anda coba koreksi. Dan saya tidak bercanda: Jujur saya maksudkan bahwa Anda harus mencobanya sendiri dan melihat apa yang terjadi. Dengan menghapus tambahan, setiap utas hanya akan mencetak karakter pertama dari string.
kotak roti
Saya awalnya menulis !!i++, tetapi mengeditnya beberapa detik kemudian, karena saya menyadari itu akan dievaluasi 0pada iterasi pertama. Saya berasumsi Anda telah melihat versi yang belum diedit. Saya tidak dapat menguji kode Anda, karena hanya mencetak karakter pertama, sekali . Ada banyak alternatif; i++<13, menggunakan !!i, atau bahkanwrite(1,"Hello World\n",i++>13||fork()||main())
primo
9

Ruby, 46 karakter

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

Ini disinkronkan karena fakta bahwa program menunggu utas berakhir sebelum memulai utas berikutnya dan melanjutkan dengan arang berikutnya.

Howard
sumber
7

Pythonect (35 karakter)

http://www.pythonect.org

"Hello World"|list|_.split()->print
Jonathan Rom
sumber
Ini adalah yang terpendek sejauh ini. Karena saya tidak tahu apa yang sebenarnya dilakukannya, saya akan menganggap itu benar dan menerimanya dalam satu atau dua hari jika tidak ada yang berbicara menentangnya atau memposting sesuatu yang lebih pendek.
Tharwen
1
Lihat saja contoh-contohnya. Tidakkah seharusnya mencetak pernyataan atau pernyataan daftar memiliki tanda kurung [] di sekitarnya?
Dalin Seivewright
1
Hai, saya meneruskan jawaban (pencipta pythonect) Itzik: '->' dan '|' keduanya adalah operator Pythonect. Operator pipa melewati satu item pada satu item, sedangkan operator lainnya melewati semua item sekaligus. Apa yang dilakukan oleh program di atas adalah, dibutuhkan string "Hello World", ubah menjadi daftar, pisahkan daftar menjadi karakter, dan kirim masing-masing karakter untuk dicetak. Dimungkinkan untuk mengoptimalkan program lebih jauh, ke yang berikut: iter ("Hello World") | cetak Apa yang dilakukannya adalah, ia mengulangi string "Hello World", dan mengirim masing-masing karakter untuk dicetak (secara sinkronisasi / pemblokiran). Salam, Itzik Kotler | ikotler.org
Leon Fedotov
bagaimana threading dilakukan di sini ???
Rohit
1
Seperti @LeonFedotov yang disebutkan, dan dari sumber pythonect (tersedia di pythonect ) setelah parsing, untuk setiap iterasi dan operator '->', threading dilakukan seperti ini: thread = threading.Thread (target = __ run, args = ([( operator, item)] + ekspresi [1:], copy.copy (globals_), copy.copy (locals_), return_value_queue, bukan iterate_literal_arrays)) thread.start ()
Jonathan Rom
6

Python ( 101 93 98)

Ini adalah solusi Peter Taylor. Ini bekerja dengan menunda pencetakan karakter ke-N oleh N detik. Lihat komentar.

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

Ini yang asli:

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

Ini berhasil karena waktu yang diperlukan untuk mencetak satu karakter lebih kecil daripada waktu yang diperlukan Python untuk menginisialisasi utas baru, oleh karena itu utas N-th akan selesai sebelum utas N + 1-th dibuat. Rupanya melanggar aturan untuk mengandalkan ini.

marinus
sumber
Anda dapat menyimpan 3 karakter dengan mengubah import sys,threadingke import sys,threading as tdan Anda dapat menyimpan 2 lagi, dengan meneruskan argumen ke Thread sebagai argumen posisi, bukan argumen kata kunci.
Joel Cornett
2
Di mana kode yang berhubungan dengan keamanan utas? Anda hanya menjalankan utas dengan harapan mereka akan berjalan dalam urutan yang sama saat Anda memulai. Ini tidak selalu benar dan pada kenyataannya merupakan "bagian sulit" dari masalah ini. Alih-alih mengoptimalkan ukuran program Anda, Anda harus mempertimbangkan kembali masalahnya: Anda tidak mendapatkannya sejak awal. Lihat gist.github.com/2761278 untuk bukti bahwa kode ini tidak berfungsi.
silviot
Perbaikan cepat. Gunakan threading.Timersebagai ganti threading.Thread. Lulus xsebagai parameter tidur.
Joel Cornett
1
Saran Joel dapat ditingkatkan 4 hinggafor x in range(11):t.Timer(x,sys.stdout.write,"Hello World"[x]).start()
Peter Taylor
1
@silviot: Saya mengeksploitasi fakta bahwa pembuatan thread melibatkan instantiasi objek, dan karenanya membutuhkan satu hingga dua pertiga milidetik pada sistem yang telah saya uji. Output karakter tidak memiliki overhead ini, hanya mengambil sepersepuluh dari waktu ini. Karenanya, ini akan "selalu" berfungsi, selama Anda tidak menimpa apa pun. Stdout di-buffer agar tidak pernah memberikan masalah juga.
marinus
4

C # 73

"hello world".ToList().ForEach(c=>Task.Run(()=>Console.Write(c)).Wait());
JJoos
sumber
tidak yakin ini memenuhi persyaratan bahwa setiap huruf dicetak melalui utasnya sendiri karena tpl dapat menggunakan kembali utas.
statichippo
Secara teori Anda benar, tetapi pada pc saya ThreadPool.GetMaxThreads atau ThreadPool.GetAvailableThreads mengembalikan nilai sekitar 1000 untuk IO dan utas pekerja.
JJoos
4

APL (Dyalog Unicode) , 28 byte SBCS

Program lengkap. Mencetak ke stderr. Terinspirasi oleh solusi marinus .

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

Cobalah online!

⍳11 11 bilangan bulat pertama

'Hello World'{... }&¨ untuk setiap integer sebagai argumen kanan ( ), muncul fungsi berikut dengan karakter yang sesuai sebagai argumen kiri ( ):

⎕DL⍵d e l ay detik argumen kanan

⍺⊣ Buang itu (penundaan efektif) yang mendukung karakter argumen-kiri

⍞← cetak itu untuk stdout tanpa tertinggal garis putus

Adám
sumber
bagaimana ⍞∘←&¨'dlroW olleH'? - Saya tidak tahu apakah ini dijamin secara teoritis tetapi sepertinya selalu mencetaknya dalam urutan yang benar
ngn
@ ngn Jelas, karena tidak ada jaminan bahwa utas akan beroperasi dalam urutan Anda memulainya, Anda harus membuat utas program Anda aman untuk memastikan output dicetak dalam urutan yang benar.
Adám
itulah kendala yang saya coba atasi, mungkin dijamin. Saya menjalankan ini 100 kali dan sepertinya penjadwal thread selalu mengambil utas dalam urutan terbalik. Atau setidaknya itulah yang terjadi ketika ada tugas ≤11. AFAIK ⍞∘←tidak terputus (atau itu? Mungkin Anda bisa bertanya kepada pengembang C?). Alat Dyalog hijau benang - 1 benang nyata berpura-pura menjadi banyak, jadi jika (hijau) beralih benang tidak dapat terjadi, pesanan adalah diprediksi.
ngn
3

Jawa (160 karakter)

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

Ya, saya tahu ini adalah bahasa yang salah untuk kode golf, saya melakukannya untuk bersenang-senang.

Malcolm
sumber
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 karakter
Pangeran John Wesley
@Prince Yep, terima kasih atas koreksinya!
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 karakter
Wouter Coekaerts
@Wouter Sangat bagus! Saya sangat merindukannya.
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 karakter
Pangeran John Wesley
2

Bash (64)

:(){ [ "$1" ]&&(echo -n "${1:0:1}"&: "${1:1}")};: "Hello World"
marinus
sumber
@marinus Golf doen oleh 3 karakter::()([ "$1" ]&&(printf "${1:0:1}"&: "${1:1}"));: Hello\ World
Digital Trauma
@fossilet Bekerja untuk saya di Linux dan OSX, beberapa versi bash. Satu atau dua karakter terakhir kadang-kadang dicetak setelah prompt 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

Saya tidak begitu yakin tentang mengalikan dengan 9999 - Saya memiliki Xeon 2Ghz yang berfungsi dengan baik bahkan jika Anda tidak, tetapi saya juga memiliki Pentium 4 yang membutuhkannya (999 memberikan output kacau dan 99 tidak t melakukan apa pun.)

marinus
sumber
Simpan 2 karakter dengan menggunakan (*5^6)alih-alih (*9999)dan tidak menggunakan backquotes untuk mapM_.
Siput mekanik
@Mechanicalsnail Jika Anda menghapus backticks Anda memerlukan sepasang kawat gigi tambahan, jika tidak mem-parsing (((mapM_ (\(x,y) ... )) zip) [0..]) ...yang tidak Anda inginkan.
marinus
Adapun 999, mungkin akan terpotong ke 0 karena keterbatasan sistem operasi, tapi saya bisa saja salah. OS apa yang Anda gunakan?
Joey Adams
2

scala ( 81 79 karakter)

def?(l:String){if(l.size!=0)new Thread{print(l(0));?(l.tail)}}
?("Hello World")
Pangeran John Wesley
sumber
Sedikit lebih pendek: def? (L: String) {if (l.size> 0) Thread baru {print (l (0));? (L.tail)}}
Joa Ebert
@ JoEbert: ya, bagus
Pangeran John Wesley
2

Groovy, 51 karakter

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

D (135 karakter)

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

Saya hanya memulai utas berikutnya ketika saya sudah mencetak karakter saat ini

sunting +2 karakter untuk pemeriksaan batas yang lebih baik

ratchet freak
sumber
Saya mendapatkan [email protected](6): Range violationkesalahan.
Fish Monitor
@fossilet saya memperbaikinya
ratchet freak
1

Scala 74

"Hello World".zipWithIndex.par.map(x=>{Thread.sleep(x._2*99);print(x._1)})
  • zipWithIndex menghasilkan ((H, 0), (e, 1), (l, 2) ...).
  • par membuatnya menjadi koleksi paralel.

Tes:

(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
Pengguna tidak diketahui
sumber
scala> "Hello World".zipWithIndex.par.foreach(x=>{Thread.sleep(x._2*99);print(x._1)}) Hel lWrolod- Saya mendapatkan ini
Pangeran John Wesley
Juga println(Thread.currentThread.getName)menunjukkan bahwa utasnya tidak unik.
Pangeran John Wesley
@ PrinceJohnWesley: Saya kira Anda perlu satu inti per huruf, sehingga par akan mendistribusikan pekerjaan di semua core.
pengguna tidak dikenal
Saya mendapatkannya. jadi satu inti per huruf + resolusi tinggi dari jam sistem diperlukan.
Pangeran John Wesley
gunakan mapsebagai ganti foreach. Anda dapat menyimpan 4 karakter.
Pangeran John Wesley
1

Javascript (72)

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

scala (45)

Utas # gabung solusi berbasis

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

atau

for(x<-"Hello World")new Thread{print(x)}join
Pangeran John Wesley
sumber
1

Ini adalah upaya F # saya. Program F # serius pertama saya. Mohon berbaik hati.

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

Pergi

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}}
singkat
sumber
Anda tidak perlu menghitung karakter - kami akan melakukannya untuk Anda!
pengguna tidak diketahui
0

Erlang (90)

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

Menyusun erlc +export_all h.erl

Nik
sumber
0

Nimrod, 121

proc p(c:char){.thread.}=write(stdout,c)
for c in "Hello World":
 var t:TThread[char]
 createThread(t,p,c)
 joinThread(t)
berhenti mengubah counterclockwis
sumber
0

Python: terlalu banyak karakter, tetapi berhasil.

# 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()
silviot
sumber
Saya tidak mengerti apa tujuan dari pengacakan waktu tidur.
Joel Cornett
@ Joel untuk memastikan bahwa, ketika berhasil, itu bukan kebetulan yang beruntung dari utas yang dieksekusi dalam urutan yang sama saat mereka dipecat.
silviot
0

C # 90 84

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

Versi yang sedang berjalan: http://ideone.com/0dXNw

Cristian Lupascu
sumber
console.write sangat cepat itulah sebabnya ini mungkin bekerja untuk Anda tetapi jelas bukan utas yang aman!
statichippo
@statichippo Anda benar; Saya memperbaikinya.
Cristian Lupascu
0

Objective-C (183 karakter)

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

Haskell 99 Karakter

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

Cara kerjanya adalah setiap utas dimulai berikutnya setelah menampilkan karakternya, sehingga sebenarnya hal-hal yang bermanfaat tidak dapat terjadi di luar urutan.

PyRulez
sumber
0

Bash , 43 byte

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

Cobalah online!

xargsbercabang printfproses terpisah untuk setiap karakter (dan menunggu itu untuk keluar).

Bash , 45 byte, tidak ada utilitas eksternal

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

Cobalah online!

Perluas (printf H); (printf e); (printf l); (printf l); (printf o); (printf \ ); (printf W); (printf o); (printf r); (printf l); (printf d);sebelum evaluasi. Tanda kurung membuat Bash garpu subkulit untuk setiap huruf (dan tunggu sampai keluar), tapi kali ini printfadalah Bash bawaan.

Anders Kaseorg
sumber