HelolW rdlo (виклик нитки)


39

У мене є виклик для вас:

  • Роздрукуйте "Hello World" будь-якою мовою.
  • Кожен символ повинен бути надрукований із власної, унікальної нитки

Це воно. Очевидно, оскільки немає гарантії, що потоки будуть працювати в тому порядку, коли ви їх запускаєте, ви повинні зробити свій потік програми безпечним, щоб забезпечити друк результатів у правильному порядку.

І, оскільки це кодовий гольф, виграє найкоротша програма.

Оновлення:

Переможець - запис APL Марінуса на 34 символи. Він також виграє приз за найменш читабельний запис.


10
Кращою назвою для цього було бHelolW rdlo
Крістіан Лупаску

Ха, мені це подобається. Змінивши його одразу: D
Тарвен

Aww ... це занадто коротко
Tharwen

1
Смішно бачити, як багато людей ігнорують натяк "очевидно, оскільки немає гарантії, що потоки працюватимуть у тому порядку, коли ви їх запускаєте", і подумайте, що вони це правильно зробили.
Джоа Еберт

Хоча це правда, що "немає жодної гарантії, що потоки будуть працювати в тому порядку, коли ви їх запускаєте", на практиці вони майже завжди будуть робити для такої тривіальної програми. Щоб уникнути цієї плутанини, я б додав до проблеми, що кожен потік повинен 1) чекати (невелике) випадкове число мілісекунд 2) вивести його char 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
Знаєш, що? Я візьму ваше слово за це ... :)
Болстер

Гаразд, це найкоротше. Вітаємо!
Тарвен

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 байти. Приємне рішення інакше.
примо

Спробуйте спробувати це і побачити, що воно виробляє.
хлібниця

Моя помилка, я мав на увазі!!++i
прима

Це, здається, те, що ви написали вперше, тому я не бачу, яку помилку ви намагалися виправити. І я не був вибагливим: я, чесно кажучи, мав би спробувати сам і подивитися, що станеться. Видаляючи додавання, кожен потік просто надрукує перший символ рядка.
хлібниця

Я спочатку писав !!i++, але відредагував це через кілька секунд, тому що зрозумів, що це оцінить 0на першій ітерації. Я припускав, що ви бачили неоредаговану версію. Я не в змозі перевірити свій код, тому що він виводить тільки найперший символ, один раз . Хоча є багато альтернатив; i++<13, використовуючи !!iабо навітьwrite(1,"Hello World\n",i++>13||fork()||main())
примо

9

Рубі, 46 символів

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

Він синхронізується через те, що програма чекає завершення потоку перед запуском наступного потоку та продовженням наступного символу.


7

Pythonect (35 символів)

http://www.pythonect.org

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

Це найкоротший поки що. Оскільки я не маю уявлення про те, що це насправді робить, я вважаю, що це правильно, і прийму це через день чи два, якщо ніхто не виступає проти цього або публікує щось коротше.
Тарвен

1
Просто переглянув приклади. Чи не слід друкувати виписку або заяву списку навколо дужок []?
Далін Сейврайт

1
Привіт, я пересилаю відповідь Ітзіка (творець пітонекта): '->' і '|' є обома операторами Pythonect. Оператор трубопроводу передає один елемент на елемент, а інший оператор передає всі елементи відразу. Програма, що описана вище, бере рядок "Hello World", перетворює її у список, розділяє список на символи та надсилає кожну таблицю для друку. Можна ще більше оптимізувати програму до наступного: iter ("Hello World") | надрукувати Що це робить, він повторює рядок "Hello World" і надсилає кожну таблицю для друку (синхронізуючи / блокуючи). З повагою, Іцик Котлер | ikotler.org
Леон Федотов

як тут робиться нарізка ???
Рохіт

1
Як і згаданий @LeonFedotov, і з джерела pythonect (доступний на pythonect ) після розбору для кожної ітерації та оператора '->', нанизування робиться так: thread = threading.Thread (target = __ run, args = ([( оператор, елемент)] + вираз [1:], copy.copy (глобальні_), copy.copy (locals_), return_value_queue, а не ітерація_literal_arrays)) thread.start ()
Джонатан Ром

6

Пітон ( 101 93 98)

Це рішення Пітера Тейлора. Він працює, затримуючи друк 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,threadingдо , import sys,threading as tі ви можете заощадити ще 2, шляхом передачі аргументів на тему , як позиційні аргументи, а не іменовані аргументів.
Джоел Корнетт

2
Де код, який стосується безпеки потоку? Ви просто запускаєте теми, сподіваючись, що вони запустяться в тому ж порядку, коли ви їх запускаєте. Це не завжди відповідає дійсності і насправді є «важкою частиною» цієї проблеми. Замість того, щоб оптимізувати розмір програми, слід переглянути проблему: ви її не отримали в першу чергу. Перегляньте сторінку gist.github.com/2761278, щоб підтвердити, що цей код не працює.
silviot

Швидке виправлення. Використовуйте threading.Timerзамість threading.Thread. Передати xяк параметр сну.
Джоел Корнетт

1
Пропозиція Джоела може бути покращена за 4 доfor x in range(11):t.Timer(x,sys.stdout.write,"Hello World"[x]).start()
Пітер Тейлор

1
@silviot: Я використовував той факт, що створення ниток передбачає екземпляр об'єкта, і таким чином займає одну-дві третини мілісекунди на тестованих системах. Вихід символів не має цієї накладних витрат, займаючи лише десяту частину цього часу. Тому це буде "завжди", доки ви нічого не перекриєте. Stdout буферизований так, що ніколи не повинно створювати проблем.
Марін

4

C # 73

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

не впевнений, що це задовольняє вимогу друкувати кожну букву через власну нитку, оскільки tpl може повторно використовувати нитки.
statichippo

Теоретично ти маєш рацію, але на моєму ПК ThreadPool.GetMaxThreads або ThreadPool.GetAvailableThreads повертає значення близько 1000 як для потоків IO, так і для робочих.
JJoos

4

APL (Dyalog Unicode) , 28 байт SBCS

Повна програма. Друкує на stderr. Натхненний розчином марінуса .

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

Спробуйте в Інтернеті!

⍳11 перші 11 цілих чисел

'Hello World'{}&¨ Для кожного цілого числа як правого аргументу ( ), породжуйте наступну функцію відповідним символом як аргумент зліва ( ):

⎕DL⍵d e l ay права аргументація секунд

⍺⊣ відмовтеся від цього (ефективна затримка) на користь символу лівого аргументу

⍞← роздрукуйте його до stdout без переривання ліній


як щодо ⍞∘←&¨'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 символів
принц Джон Веслі

@Prince Yep, дякую за виправлення!
Малькольм

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
@ Малькольм, @ bkil, @ Вутер: 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 символів
Принц Джон Веслі

2

Баш (64)

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

@marinus Golfed зроблено на 3 години::()([ "$1" ]&&(printf "${1:0:1}"&: "${1:1}"));: Hello\ World
Digital Trauma

@fossilet працює для мене як в Linux, так і в OSX, декількох версіях bash. Останній один або два символи іноді друкується після підказки оболонки.
Цифрова травма

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 - у мене є 2 ГГц Xeon, на якому він буде добре працювати, навіть якщо ви цього не зробите, але у мене також є Pentium 4, який йому потрібен (999 дав неприємний вихід і 99 didn ' t взагалі нічого не роблю.)


Збережіть 2 символи, використовуючи (*5^6)замість (*9999)і не використовуючи зворотні цитати для mapM_.
Механічний равлик

@Mechanicalsnail Якщо ви видалите задні посилання, вам потрібна додаткова пара дужок, інакше вона розбирає те, (((mapM_ (\(x,y) ... )) zip) [0..]) ...що вам не потрібно.
Марина

Що стосується 999, воно може бути скороченим до 0 через обмеження операційної системи, але я можу помилитися. Яку ОС ви використовуєте?
Джої Адамс



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

Scala 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

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

Ерланг (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, щоб переконатися, що, коли це працює, це не випадковий збіг потоків, які виконуються в тому ж порядку, як вони були запущені.
сильвіот


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

Баш , 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 fork для підкреслення кожної літери (і чекайте, поки вона вийде), але на цей раз printfце Bash вбудований.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.