HelolW rdlo (ความท้าทายการเธรด)


39

ฉันมีความท้าทายสำหรับคุณ:

  • พิมพ์ "Hello World" โดยใช้ภาษาใดก็ได้
  • อักขระแต่ละตัวจะต้องพิมพ์จากเธรดที่ไม่ซ้ำใคร

แค่นั้นแหละ. เห็นได้ชัดว่าไม่มีการรับประกันว่าเธรดจะทำงานตามลำดับที่คุณเริ่มต้นคุณต้องทำให้เธรดโปรแกรมของคุณปลอดภัยเพื่อให้แน่ใจว่าผลลัพธ์จะถูกพิมพ์ในลำดับที่ถูกต้อง

และเนื่องจากนี่คือรหัสกอล์ฟโปรแกรมที่สั้นที่สุดชนะ

ปรับปรุง:

ผู้ชนะคือรายการ APL ของ Marinusที่ 34 ตัวอักษร นอกจากนี้ยังชนะรางวัลสำหรับการอ่านที่น้อยที่สุด


10
ชื่อที่ดีขึ้นสำหรับสิ่งนี้น่าจะเป็นHelolW rdlo
Cristian Lupascu

ฉันชอบอย่างนั้น เปลี่ยนได้ทันที: D
Tharwen

อ้าว ... มันสั้นเกินไป
Tharwen

1
เป็นเรื่องตลกที่จะเห็นว่ามีคนจำนวนมากที่ไม่สนใจ "ชัดเจนเนื่องจากไม่มีการรับประกันว่าเธรดจะทำงานตามลำดับที่คุณเริ่ม" คำแนะนำและคิดว่าพวกเขาทำให้ถูกต้อง
Joa Ebert

แม้ว่าจะเป็นความจริงที่ว่า "ไม่มีการรับประกันว่าเธรดจะทำงานตามลำดับที่คุณเริ่ม" ในทางปฏิบัติพวกเขามักจะทำเพื่อโปรแกรมที่น่าสนใจเช่นนี้ เพื่อหลีกเลี่ยงความสับสนนี้ฉันจะเพิ่มปัญหาที่แต่ละเธรดต้อง 1) รอ (เล็ก) สุ่มจำนวนมิลลิวินาที 2) ส่งออกถ่าน 3) รออีกครั้ง (อาจจะนาน) วิธีนี้ผู้คนสามารถบอกได้ว่า รหัสใช้งานได้โดยเรียกใช้สองสามครั้ง และการแก้ปัญหาการเข้าร่วม () จะทำงานได้แย่ลงมาก หากไม่มีการรอแบบสุ่มอาจทำให้เข้าใจผิดได้ว่าประสบความสำเร็จในการคิดว่าโปรแกรมของเขาถูกต้อง
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
คุณรู้อะไรไหม? ฉันจะเอาคำพูดของคุณไปใช้ ... :)
หนุน

ตกลงนี่เป็นระยะสั้นที่สุด ขอแสดงความยินดี!
Tharwen

19

C, 61 62 ตัวอักษร

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

ฟังก์ชั่นห้องสมุด pthread ทั้งหมดมีชื่อ loooooong ดังนั้นฉันจึงใช้กระบวนการที่แยกต่างหากทั้งหมดสำหรับตัวละครแต่ละตัว fork()สั้นกว่ามาก

มันจำเป็นต้องใช้write()แทนputchar()เพราะฟังก์ชั่นการบัฟเฟอร์ stdio ไม่ปลอดภัยต่อเธรด

แก้ไข : สำรองสูงสุด 62 ตัวอักษร ในความกระตือรือร้นของฉันลดลงถึง 61 ตัวอักษรยังลดความปลอดภัยของด้าย


มันควรจะเป็นไปได้ที่จะเปลี่ยนคำสั่งเขียนwrite(1,"Hello World\n",!!++i)เป็น 2 ไบต์ วิธีการแก้ปัญหาที่ดีเป็นอย่างอื่น
โม่

คุณควรลองสิ่งนั้นและดูว่ามันผลิตอะไร
breadbox

ความผิดพลาดของฉันฉันหมายถึง!!++i
โม่

นั่นเป็นสิ่งที่คุณเขียนในครั้งแรกดังนั้นฉันจึงไม่เห็นความผิดพลาดที่คุณพยายามแก้ไข และฉันก็ไม่ได้เป็นคนขี้กลัว: ฉันหมายความว่าคุณควรลองเอง โดยการลบการเพิ่มทุกกระทู้จะพิมพ์ตัวอักษรตัวแรกของสตริง
breadbox

ตอนแรกฉันเขียน!!i++แต่ก็แก้ไขได้ไม่กี่วินาทีต่อมาเพราะฉันรู้ว่ามันจะประเมิน0ในการทำซ้ำครั้งแรก ฉันคิดว่าคุณเคยเห็นเวอร์ชันที่ไม่มีการแก้ไข ฉันไม่สามารถทดสอบรหัสของคุณได้เพราะจะพิมพ์ตัวอักษรแรกสุดเพียงครั้งเดียวเท่านั้น มีหลายทางเลือกแม้ว่า; i++<13ใช้!!iหรือแม้กระทั่งwrite(1,"Hello World\n",i++>13||fork()||main())
โม่

9

Ruby, 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") | พิมพ์สิ่งที่มันทำคือมันทำซ้ำสตริง "Hello World" และส่งตัวอักษรแต่ละตัวเพื่อพิมพ์ (ในลักษณะซิงค์ / บล็อก) ขอแสดงความนับถือ Itzik Kotler | ikotler.org
Leon Fedotov

การทำเกลียวอยู่ที่นี่ได้อย่างไร ???
Rohit

1
เช่นเดียวกับ @LeonFedotov ที่กล่าวถึงและจากแหล่ง pythonect (มีให้ที่pythonect ) หลังจากการแยกวิเคราะห์สำหรับแต่ละการวนซ้ำและตัวดำเนินการ '->' การทำเกลียวจะทำดังนี้: thread = threading.Thread (target = __ run, args = ([( โอเปอเรเตอร์, รายการ)] + นิพจน์ [1:], copy.copy (globals_), copy.copy (locals_), return_value_queue, ไม่ใช่ iterate_literal_arrays)) thread.start ()
Jonathan Rom

6

Python ( 101 93 98)

นี่คือทางออกของ Peter Taylor มันทำงานได้โดยการล่าช้าการพิมพ์ตัวอักษร N - th โดย 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-th จะเสร็จสิ้นก่อนที่เธรด N + 1-th จะถูกสร้างขึ้น เห็นได้ชัดว่ามันขัดกับกฎที่ต้องพึ่งพาสิ่งนี้


คุณสามารถบันทึกได้ 3 ตัวอักษรโดยเปลี่ยนimport sys,threadingเป็นimport sys,threading as tและคุณสามารถบันทึกได้อีก 2 ตัวโดยส่งผ่านอาร์กิวเมนต์ไปยัง Thread เป็น args ตำแหน่งมากกว่าอาร์กิวเมนต์ของคำหลัก
Joel Cornett

2
รหัสที่เกี่ยวข้องกับความปลอดภัยของกระทู้อยู่ที่ไหน คุณเพิ่งเริ่มต้นเธรดโดยหวังว่าพวกเขาจะทำงานในลำดับเดียวกันกับที่คุณเริ่ม สิ่งนี้จะไม่เป็นจริงเสมอไปและในความเป็นจริง "ส่วนที่ยาก" ของปัญหานี้ แทนที่จะปรับขนาดโปรแกรมให้เหมาะสมคุณควรพิจารณาปัญหาใหม่อีกครั้ง: คุณไม่ได้รับมันมาตั้งแต่แรก ดูgist.github.com/2761278เพื่อพิสูจน์ว่ารหัสนี้ใช้ไม่ได้
silviot

แก้ไขด่วน ใช้แทนthreading.Timer threading.Threadส่งผ่านxเป็นพารามิเตอร์ sleep
Joel Cornett

1
คำแนะนำของ Joel สามารถปรับปรุงได้โดย 4 ถึงfor x in range(11):t.Timer(x,sys.stdout.write,"Hello World"[x]).start()
Peter Taylor

1
@silviot: ฉันใช้ประโยชน์จากข้อเท็จจริงที่ว่าการสร้างเธรดเกี่ยวข้องกับการทำให้วัตถุเป็นอินสแตนซ์และใช้เวลาหนึ่งถึงสองในสามของมิลลิวินาทีในระบบที่ฉันทดสอบ เอาต์พุตอักขระไม่มีโอเวอร์เฮดนี้ใช้เพียงหนึ่งในสิบของเวลานี้ ดังนั้นมันจะทำงาน "เสมอ" ตราบใดที่คุณไม่ได้แทนที่อะไร Stdout ถูกบัฟเฟอร์ดังนั้นจึงไม่ควรให้ปัญหาเช่นกัน
marinus

4

C # 73

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

ไม่แน่ใจว่าสิ่งนี้ตรงตามข้อกำหนดที่แต่ละจดหมายจะพิมพ์ผ่านเธรดของตัวเองเนื่องจาก tpl อาจนำเธรดมาใช้ซ้ำ
statichippo

ในทางทฤษฎีคุณถูกต้อง แต่ในพีซีของฉัน ThreadPool.GetMaxThreads หรือ ThreadPool.GetAvailableThreads คืนค่าประมาณ 1,000 สำหรับทั้ง IO และเธรดผู้ปฏิบัติงาน
JJoos

4

APL (Dyalog Unicode) , 28 ไบต์SBCS

โปรแกรมเต็มรูปแบบ พิมพ์ไปยัง stderr แรงบันดาลใจจากการแก้ปัญหา marinus'

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

ลองออนไลน์!

⍳11 11 จำนวนเต็มแรก

'Hello World'{}&¨ สำหรับแต่ละจำนวนเต็มว่าเป็นอาร์กิวเมนต์ที่ถูกต้อง ( ) ให้วางฟังก์ชันต่อไปนี้โดยใช้อักขระที่สอดคล้องกันเป็นอาร์กิวเมนต์ซ้าย ( ):

⎕DL⍵dอีลิตร Ay วินาทีขวาโต้แย้ง

⍺⊣ ยกเลิก (ความล่าช้าอย่างมีประสิทธิภาพ) เพื่อสนับสนุนอักขระการโต้แย้งด้านซ้าย

⍞← พิมพ์ที่ stdout โดยไม่ต้องตามตัวแบ่งบรรทัด


แล้วไง⍞∘←&¨'dlroW olleH'ล่ะ - ฉันไม่รู้ว่ามันรับประกันในทางทฤษฎีหรือไม่ แต่ดูเหมือนว่าจะพิมพ์ออกมาตามลำดับที่ถูกต้อง
เสมอ

@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
เจ้าชายจอห์นเวสลีย์

@ Prince Yep ขอบคุณสำหรับการแก้ไข!
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 chars
Wouter Coekaerts

@ คนดีมากคนหนึ่ง! ฉันคิดถึงมันทั้งหมด
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 chars
Prince John Wesley

2

Bash (64)

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

@marinus Golfed doen โดย 3 ตัวอักษร::()([ "$1" ]&&(printf "${1:0:1}"&: "${1:1}"));: Hello\ World
บาดเจ็บดิจิตอล

@fossilet ใช้ได้กับฉันทั้ง Linux และ OSX รุ่นทุบตีหลายรุ่น บางครั้งอักขระหนึ่งหรือสองตัวสุดท้ายจะถูกพิมพ์หลังจากเชลล์พรอมต์
บาดเจ็บทางดิจิตอล

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

ฉันไม่แน่ใจเกี่ยวกับการคูณด้วย 9999 - ฉันมี 2Ghz Xeon ซึ่งมันจะทำงานได้ดีแม้ว่าคุณจะทำไม่ได้ แต่ฉันก็มี Pentium 4 ที่ต้องการ (999 ให้ผลลัพธ์ที่อ่านไม่ออกและ 99 didn ' ไม่ทำอะไรเลย)


บันทึก 2 ตัวอักษรโดยใช้(*5^6)แทนและไม่ได้ใช้สำหรับ(*9999) backquotes mapM_
หอยทากเชิงกล

@ Mechanicalsnail ถ้าคุณเอา backticks ออกมาคุณจำเป็นต้องมีเหล็กดัดคู่อื่น ๆ มิฉะนั้นมันจะแยกวิเคราะห์ตาม(((mapM_ (\(x,y) ... )) zip) [0..]) ...ที่คุณไม่ต้องการ
marinus

สำหรับ999มันอาจจะถูกตัดเป็น 0 เนื่องจากข้อ จำกัด ของระบบปฏิบัติการ แต่ฉันอาจจะผิด คุณใช้ระบบปฏิบัติการอะไร?
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..$]);
}

ฉันจะเริ่มหัวข้อถัดไปเมื่อฉันพิมพ์ char ปัจจุบันแล้ว

แก้ไข +2 chars เพื่อการตรวจสอบที่ถูกต้องยิ่งขึ้น


ฉันได้รับcore.exception.RangeError@test.d(6): Range violationข้อผิดพลาด
Fish Monitor

@fossilet ฉันแก้ไขแล้ว
ratchet freak

1

สกาล่า 74

"Hello World".zipWithIndex.par.map(x=>{Thread.sleep(x._2*99);print(x._1)})
  • zipWithIndex สร้าง ((H, 0), (e, 1), (l, 2) ... )
  • ตราไว้หุ้นละทำให้มันเป็นคอลเลกชันแบบขนาน

แบบทดสอบ:

(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)แสดงให้เห็นว่าหัวข้อที่ไม่ซ้ำกัน
เจ้าชายจอห์นเวสลีย์

@ ปรินซ์จอห์นเวสลีย์: ฉันคิดว่าคุณต้องมีหนึ่งคอร์ต่อตัวอักษรดังนั้นพาร์จะกระจายงานทั่วคอร์ทั้งหมด
ผู้ใช้ที่ไม่รู้จัก

ฉันเข้าใจแล้ว. ดังนั้นหนึ่งคอร์ต่อตัวอักษร + ความละเอียดสูงของนาฬิการะบบที่ต้องการ
เจ้าชายจอห์นเวสลีย์

ใช้แทนmap foreachคุณสามารถบันทึกได้ 4 ตัวอักษร
เจ้าชายจอห์นเวสลีย์



1

นี่คือความพยายาม F # ของฉัน โปรแกรม F # ร้ายแรงครั้งแรกของฉัน กรุณาใจดี

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


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 Cornett

@ 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

@stichippo คุณพูดถูก; ฉันแก้ไขมันแล้ว
Cristian Lupascu

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'

ลองออนไลน์!

xargsแยกprintfกระบวนการที่แยกต่างหากสำหรับแต่ละอักขระ (และรอให้กระบวนการออกจาก)

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.