HelolWrdlo (Một thử thách luồng)


39

Tôi có một thử thách cho bạn:

  • In "Hello World" bằng bất kỳ ngôn ngữ nào.
  • Mỗi ký tự phải được in từ chủ đề độc đáo của riêng mình

Đó là nó. Rõ ràng, vì không có gì đảm bảo rằng các luồng sẽ hoạt động theo thứ tự bạn khởi động chúng, bạn phải làm cho luồng chương trình của bạn an toàn để đảm bảo đầu ra được in theo đúng thứ tự.

Và, bởi vì đây là mã golf, chương trình ngắn nhất sẽ thắng.

Cập nhật:

Người chiến thắng là mục APL của Marinus , với 34 ký tự. Nó cũng giành giải thưởng cho mục nhập ít đọc nhất.


10
Một cái tên tốt hơn cho điều này sẽ làHelolW rdlo
Cristian Lupascu

Ha, tôi thích điều đó. Thay đổi nó ngay lập tức: D
Tharwen

À ... nó quá ngắn
Tharwen

1
Thật buồn cười khi thấy có bao nhiêu người bỏ qua "rõ ràng, vì không có gì đảm bảo rằng các luồng sẽ hoạt động theo thứ tự bạn bắt đầu chúng" và nghĩ rằng họ đã hiểu đúng.
Joa Ebert

Mặc dù đúng là "không có gì đảm bảo rằng các luồng sẽ hoạt động theo thứ tự bạn khởi động chúng" trong thực tế, chúng hầu như sẽ luôn luôn làm cho một chương trình tầm thường như vậy. Để tránh sự nhầm lẫn này, tôi đã thêm vào một vấn đề là mỗi luồng phải 1) đợi một số lượng nhỏ (nhỏ) ngẫu nhiên của mili giây 2) xuất ra char 3) chờ một khoảng thời gian ngẫu nhiên (có thể dài) khác theo cách này mọi người có thể biết nếu mã này hoạt động chỉ bằng cách chạy nó một vài lần. Và các giải pháp tham gia () sẽ thực hiện tồi tệ hơn nhiều. Không có sự chờ đợi ngẫu nhiên, người ta có thể bị đánh lừa bởi một lần chạy thành công để nghĩ rằng chương trình của mình là chính xác.
silviot

Câu trả lời:


10

APL (Dyalog) ( 44 43 39 34)

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

Giải trình:

  • 2 11⍴'Hello World',⍳11 tạo ma trận: (H, 1), (e, 2), ...
  • &⌿ có nghĩa là: đối với mỗi cột của ma trận, hãy thực hiện trên một luồng riêng biệt:
  • Trong một chủ đề, bây giờ là nhân vật và bây giờ là thời gian
  • ⎕DL⊃⍵Chờ đợi trong vài giây.
  • Sau đó, ⍞←⍺xuất ký tự.

11
Bạn biết gì? Tôi sẽ tin lời bạn ... :)
Bolster

OK, đây là ngắn nhất. Xin chúc mừng!
Tharwen

19

C, 61 62 ký tự

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

Tất cả các chức năng thư viện pthread đều có tên loooooong, vì vậy thay vào đó tôi đã khởi động toàn bộ một quy trình riêng cho mỗi nhân vật. fork()ngắn hơn rất nhiều

Nó là cần thiết để sử dụng write()thay putchar()vì bởi vì các chức năng đệm stdio không an toàn cho luồng.

Đã chỉnh sửa : Sao lưu tới 62 ký tự. Trong lòng nhiệt thành của tôi, giảm xuống còn 61 ký tự cũng giảm độ an toàn của luồng.


Có thể thay đổi câu lệnh ghi thành write(1,"Hello World\n",!!++i)2 byte. Giải pháp tốt đẹp khác.
primo

Bạn nên thử điều đó và xem những gì nó tạo ra.
hộp bánh mì

Sai lầm của tôi, ý tôi là!!++i
primo

Đó dường như là những gì bạn đã viết lần đầu tiên, vì vậy tôi không thấy bạn đang cố gắng sửa lỗi gì. Và tôi đã không tỏ ra lãnh đạm: Tôi thực sự muốn nói rằng bạn nên tự mình thử nó và xem điều gì sẽ xảy ra. Bằng cách loại bỏ bổ sung, mỗi luồng sẽ chỉ in ký tự đầu tiên của chuỗi.
hộp bánh mì

Tôi đã viết ban đầu !!i++, nhưng đã chỉnh sửa nó vài giây sau đó, vì tôi nhận ra rằng nó sẽ đánh giá 0vào lần lặp đầu tiên. Tôi giả sử bạn đã thấy phiên bản chưa được chỉnh sửa. Tôi không thể kiểm tra mã của bạn, bởi vì nó chỉ in ra ký tự đầu tiên, một lần . Có rất nhiều lựa chọn thay thế mặc dù; i++<13, sử dụng !!i, hoặc thậm chíwrite(1,"Hello World\n",i++>13||fork()||main())
primo

9

Ruby, 46 ký tự

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

Nó được đồng bộ hóa do thực tế là chương trình đợi luồng kết thúc trước khi bắt đầu luồng tiếp theo và tiếp tục với char tiếp theo.


7

Pythonect (35 ký tự)

http://www.pythonect.org

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

Đây là ngắn nhất cho đến nay. Vì tôi không biết nó thực sự làm gì, tôi sẽ cho rằng nó đúng và chấp nhận nó trong một hoặc hai ngày nếu không ai lên tiếng chống lại nó hoặc đăng bất cứ điều gì ngắn hơn.
Tharwen

1
Chỉ cần có một cái nhìn ngắn gọn về các ví dụ. Không nên in câu lệnh hoặc câu lệnh liệt kê có dấu ngoặc [] xung quanh nó?
Dalin Seivewright

1
Xin chào, tôi đang chuyển tiếp câu trả lời của Itzik (người tạo ra pythonect): '->' và '|' là cả hai toán tử Pythonect. Toán tử đường ống chuyển một mục tại một mục, trong khi toán tử khác chuyển tất cả các mục cùng một lúc. Những gì chương trình trên thực hiện là, nó lấy chuỗi "Hello World", biến nó thành một danh sách, chia danh sách thành ký tự và gửi từng ký tự để in. Có thể tối ưu hóa chương trình hơn nữa, theo cách sau: iter ("Hello World") | in Nó là gì, nó lặp lại chuỗi "Hello World" và gửi từng char để in (theo cách đồng bộ / chặn). Trân trọng, Itzik Kotler | ikotler.org
Leon Fedotov

làm thế nào là luồng được thực hiện ở đây ???
Rohit

1
Giống như @LeonFedotov đã đề cập và từ nguồn pythonect (có sẵn tại pythonect ) sau khi phân tích cú pháp, với mỗi lần lặp và toán tử '->', việc phân luồng được thực hiện như sau: thread = threading.Thread (target = __ run, args = ([( toán tử, mục)] + biểu thức [1:], copy.copy (continals_), copy.copy (locals_), return_value_queue, không phải iterate_literal_arrays)) thread.start ()
Jonathan Rom

6

Con trăn ( 101 93 98)

Đây là giải pháp của Peter Taylor. Nó hoạt động bằng cách trì hoãn in ký tự N-th bằng N giây. Xem ý kiến.

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

Đây là bản gốc:

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

Nó hoạt động vì thời gian để in một ký tự ít hơn thời gian Python cần để khởi tạo một luồng mới, do đó, luồng thứ N sẽ kết thúc trước khi luồng N + 1 được tạo. Rõ ràng nó là trái với các quy tắc để dựa vào điều này.


Bạn có thể lưu 3 ký tự bằng cách thay đổi import sys,threadingthành import sys,threading as tvà bạn có thể lưu thêm 2 ký tự , bằng cách chuyển các đối số cho Chủ đề dưới dạng đối số vị trí, thay vì đối số từ khóa.
Joel Cornett

2
Đâu là mã liên quan đến an toàn luồng? Bạn chỉ bắn các luồng hy vọng chúng sẽ chạy theo thứ tự bạn khởi động chúng. Điều này sẽ không luôn luôn đúng và thực tế là "phần khó" của vấn đề này. Thay vì tối ưu hóa kích thước chương trình của bạn, bạn nên xem xét lại vấn đề: bạn đã không giải quyết nó ngay từ đầu. Xem gist.github.com/2761278 để biết bằng chứng rằng mã này không hoạt động.
silviot

Khắc phục nhanh. Sử dụng threading.Timerthay vì threading.Thread. Truyền vào xnhư tham số giấc ngủ.
Joel Cornett

1
Gợi ý của Joel có thể được cải thiện từ 4 đếnfor x in range(11):t.Timer(x,sys.stdout.write,"Hello World"[x]).start()
Peter Taylor

1
@silviot: Tôi đã khai thác thực tế rằng việc tạo luồng liên quan đến việc khởi tạo một đối tượng và do đó mất một đến hai phần ba của một phần nghìn giây trên các hệ thống mà tôi đã thử nghiệm. Đầu ra của nhân vật không có chi phí này, chỉ chiếm một phần mười thời gian này. Do đó, nó sẽ "luôn luôn" hoạt động, miễn là bạn không ghi đè lên bất cứ điều gì. Stdout được đệm để không bao giờ đưa ra vấn đề.
bến tàu

4

C # 73

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

không chắc chắn điều này đáp ứng yêu cầu rằng mỗi chữ cái được in qua luồng riêng vì tpl có thể sử dụng lại các luồng.
statichippo

Về lý thuyết bạn đúng, nhưng trên máy tính của tôi ThreadPool.GetMaxThreads hoặc ThreadPool.GetAv AvailableThreads trả về giá trị khoảng 1000 cho cả chủ đề IO và worker.
JJoos

4

APL (Dyalog Unicode) , 28 byte SBCS

Chương trình đầy đủ. In ra stderr. Lấy cảm hứng từ giải pháp của bến .

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

Hãy thử trực tuyến!

⍳11 11 số nguyên đầu tiên

'Hello World'{Chiếm }&¨ cho mỗi số nguyên là đối số bên phải ( ), sinh ra hàm sau với ký tự tương ứng là đối số bên trái ( ):

⎕DL⍵d e l ay giây đối số đúng

⍺⊣ loại bỏ rằng (độ trễ hiệu quả) có lợi cho ký tự bên trái

⍞← in nó ra thiết bị xuất chuẩn mà không ngắt dòng


làm thế nào về ⍞∘←&¨'dlroW olleH'? - Tôi không biết liệu nó có được bảo đảm về mặt lý thuyết hay không nhưng dường như luôn in chúng theo đúng thứ tự
ngn

@ngn Rõ ràng, vì không có gì đảm bảo rằng các luồng sẽ hoạt động theo thứ tự bạn khởi động chúng, bạn phải làm cho luồng chương trình của bạn an toàn để đảm bảo đầu ra được in theo đúng thứ tự.
Adám

đó là hạn chế mà tôi đang cố gắng giải quyết, nó có thể được đảm bảo. Tôi đã chạy nó 100 lần và có vẻ như bộ lập lịch luồng luôn chọn các luồng theo thứ tự ngược lại. Hoặc ít nhất đó là trường hợp khi có ≤11 nhiệm vụ. AFAIK ⍞∘←không bị gián đoạn (hoặc là nó? Có lẽ bạn có thể hỏi một nhà phát triển C?). Dyalog thực hiện các luồng màu xanh lá cây - 1 luồng thực sự giả vờ là nhiều, vì vậy nếu chuyển đổi luồng (màu xanh lá cây) không thể xảy ra, thứ tự thể dự đoán được.
ngn

3

Java (160 ký tự)

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

Vâng, tôi biết đây là ngôn ngữ sai cho mã golf, tôi làm nó cho vui.


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 ký tự
Hoàng tử John Wesley

@Prince Yep, cảm ơn đã sửa!
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

@Wouter Rất tốt! Tôi hoàn toàn nhớ nó
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 ký tự
Hoàng tử John Wesley


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

Tôi không chắc chắn về việc nhân với 9999 - Tôi có Xeon 2Ghz, nó sẽ hoạt động tốt ngay cả khi bạn không, nhưng tôi cũng có Pentium 4 cần nó (999 cho đầu ra bị cắt xén và 99 không ' t làm bất cứ điều gì cả.)


Lưu 2 ký tự bằng cách sử dụng (*5^6)thay vì (*9999)và không sử dụng backquote cho mapM_.
Ốc cơ khí

@M cơsnail Nếu bạn loại bỏ các backticks bạn cần thêm một cặp niềng răng, nếu không nó sẽ phân tích cú pháp như (((mapM_ (\(x,y) ... )) zip) [0..]) ...bạn không muốn.
bến tàu

Về phần 999, nó có thể bị cắt ngắn về 0 do giới hạn của hệ điều hành, nhưng tôi có thể sai. Bạn đang sử dụng hệ điều hành nào?
Joey Adams



1

D (135 ký tự)

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

Tôi chỉ bắt đầu chuỗi tiếp theo khi tôi đã in char hiện tại

chỉnh sửa ký tự +2 để kiểm tra ràng buộc tốt hơn


Tôi nhận được core.exception.RangeError@test.d(6): Range violationlỗi.
Giám sát cá

@fossilet Tôi đã sửa nó
ratchet freak

1

Scala 74

"Hello World".zipWithIndex.par.map(x=>{Thread.sleep(x._2*99);print(x._1)})
  • zipWith Index tạo ra ((H, 0), (e, 1), (l, 2) ...).
  • mệnh làm cho nó một bộ sưu tập song song.

Các xét nghiệm:

(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- Tôi hiểu rồi
Hoàng tử John Wesley

Cũng println(Thread.currentThread.getName)cho thấy rằng các chủ đề không phải là duy nhất.
Hoàng tử John Wesley

@PrinceJohnWesley: Tôi đoán bạn cần một lõi cho mỗi chữ cái, để mệnh sẽ phân phối công việc trên tất cả các lõi.
người dùng không xác định

Tôi đạt được rồi. vì vậy một lõi cho mỗi chữ cái + độ phân giải cao của đồng hồ hệ thống cần thiết.
Hoàng tử John Wesley

sử dụng mapthay vì foreach. bạn có thể lưu 4 ký tự.
Hoàng tử John Wesley

1

Javascript (72)

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

1

scala (45)

Giải pháp dựa trên chủ đề # tham gia

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

hoặc là

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

1

Đây là nỗ lực F # của tôi. Chương trình F # nghiêm túc đầu tiên của tôi. Làm ơn.

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

0

Đi

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

Bạn không cần phải đếm các ký tự - chúng tôi sẽ làm như vậy cho bạn!
người dùng không xác định

0

Erlang (90)

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

Biên dịch erlc +export_all h.erl



0

Python: quá nhiều ký tự, nhưng nó hoạt động.

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

Tôi không hiểu mục đích của việc ngẫu nhiên thời gian ngủ là gì.
Joel Cornett

@Joel để đảm bảo rằng, khi nó hoạt động, đó không phải là sự trùng hợp may mắn của các luồng được thực hiện theo đúng thứ tự khi chúng bị bắn.
silviot

0

C # 90 84

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

Phiên bản đang chạy: http://ideone.com/0dXNw


console.write rất nhanh, đó là lý do tại sao điều này có thể làm việc cho bạn nhưng chắc chắn không phải là chủ đề an toàn!
statichippo

@statichippo bạn nói đúng; Tôi đã sửa nó.
Cristian Lupascu

0

Mục tiêu-C (183 ký tự)

-(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 Nhân vật

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

Cách thức hoạt động là mỗi luồng bắt đầu tiếp theo sau khi đã hiển thị ký tự của nó, vì vậy chúng thực sự là những thứ hữu ích không thể xảy ra ngoài chuỗi.


0

Bash , 43 byte

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

Hãy thử trực tuyến!

xargstạo ra một printfquy trình riêng cho mỗi nhân vật (và chờ cho nó thoát ra).

Bash , 45 byte, không có tiện ích bên ngoài

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

Hãy thử trực tuyến!

Mở rộng để (printf H); (printf e); (printf l); (printf l); (printf o); (printf \ ); (printf W); (printf o); (printf r); (printf l); (printf d);trước khi đánh giá. Các dấu ngoặc đơn làm cho Bash fork là một nhánh con cho mỗi chữ cái (và đợi nó thoát ra), nhưng lần này printflà hàm dựng sẵn của Bash.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.