HelolW rdlo (Um desafio de enfiar)


39

Eu tenho um desafio para você:

  • Imprima "Hello World" usando qualquer idioma.
  • Cada caractere deve ser impresso a partir de seu próprio e exclusivo thread

É isso aí. Obviamente, como não há garantia de que os encadeamentos operem na ordem em que você os inicia, você deve tornar o encadeamento do programa seguro para garantir que a saída seja impressa na ordem correta.

E, como se trata de código de golfe, o programa mais curto vence.

Atualizar:

O vencedor é a inscrição de Marinus na APL , com 34 caracteres. Ele também ganha o prêmio pela entrada menos legível.


10
Um nome melhor para este teria sidoHelolW rdlo
Cristian Lupascu

Ah, eu gosto disso. Alterando-o imediatamente: D
Tharwen

Aww ... é muito curto
Tharwen

1
É engraçado ver quantas pessoas ignoram a dica "obviamente, pois não há garantia de que os threads funcionem na ordem em que você os inicia" e pensam que eles acertaram.
Joa Ebert #

Embora seja verdade que "não há garantia de que os encadeamentos operem na ordem em que você os inicia", na prática, eles quase sempre o fazem para um programa tão trivial. Para evitar essa confusão, acrescentaria ao problema que cada encadeamento deve 1) esperar um (pequeno) número aleatório de milissegundos 2) produzir seu caractere 3) aguardar outro período de tempo aleatório (talvez longo) Desta maneira as pessoas poderiam saber se o código funciona executando-o algumas vezes. E as soluções join () teriam um desempenho muito pior. Sem espera aleatória, alguém poderia ser enganado por uma execução bem-sucedida para pensar que seu programa está correto.
21412 silviot

Respostas:


10

APL (Dyalog) ( 44 43 39 34)

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

Explicação:

  • 2 11⍴'Hello World',⍳11 cria uma matriz: (H, 1), (e, 2), ...
  • &⌿ significa: para cada coluna da matriz, faça em um thread separado:
  • Em um tópico, agora é o personagem e agora é a hora
  • ⎕DL⊃⍵espera por segundos.
  • Em seguida, ⍞←⍺gera o caractere.

11
Você sabe o que? Vou levar a sua palavra para ela ... :)
Bolster

OK, este é o mais curto. Parabéns!
Tharwen

19

C, 61 62 caracteres

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

Todas as funções da biblioteca pthread têm nomes demais; portanto, iniciei um processo separado inteiro para cada personagem. fork()é muito mais curto.

Era necessário usar em write()vez de, putchar()porque as funções de buffer stdio não são seguras para threads.

Editado : faça backup de 62 caracteres. No meu zelo, cair para 61 caracteres também diminuiu a segurança dos fios.


Deve ser possível alterar a instrução de gravação write(1,"Hello World\n",!!++i)para 2 bytes. Solução agradável caso contrário.
Primo

Você deve tentar isso e ver o que produz.
Breadbox

Meu erro, eu quis dizer!!++i
primo

Parece que foi o que você escreveu pela primeira vez, então não vejo qual erro você estava tentando corrigir. E eu não estava sendo ridículo: sinceramente quis dizer que você deveria tentar e ver o que acontece. Ao remover a adição, cada thread imprime apenas o primeiro caractere da string.
Breadbox

Escrevi originalmente !!i++, mas o editei alguns segundos depois, porque percebi que ele seria avaliado 0na primeira iteração. Presumi que você tivesse visto a versão não editada. Não consigo testar seu código, porque ele imprime apenas o primeiro caractere, uma vez . Existem muitas alternativas; i++<13, using !!i, or evenwrite(1,"Hello World\n",i++>13||fork()||main())
primo

9

Ruby, 46 caracteres

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

Ele é sincronizado devido ao fato de o programa aguardar o término do thread antes de iniciar o próximo thread e continuar com o próximo caractere.


7

Pythonect (35 caracteres)

http://www.pythonect.org

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

Este é o mais curto até agora. Como não tenho ideia do que realmente faz, vou assumir que está correto e aceitá-lo em um dia ou dois, se ninguém se manifestar contra ou postar algo mais curto.
Tharwen

1
Acabei de dar uma breve olhada nos exemplos. A declaração de impressão ou lista não deve conter colchetes [] ao redor?
Dalin Seivewright

1
Olá, estou encaminhando a resposta do Itzik (criador do pythonect): '->' e '|' são ambos operadores Pythonect. O operador do tubo passa um item por item, enquanto o outro operador passa todos os itens de uma só vez. O que o programa acima faz é pegar a string "Hello World", transformá-la em uma lista, dividir a lista em caracteres e enviar cada caracter para impressão. É possível otimizar ainda mais o programa, para o seguinte: iter ("Hello World") | print O que ele faz é: itera a string "Hello World" e envia cada caractere para impressão (de maneira sincronizada / bloqueada). Atenciosamente, Itzik Kotler | ikotler.org
Leon Fedotov

como a rosca está sendo feita aqui ???
Rohit

1
Como o @LeonFedotov mencionado e da fonte pythonect (disponível no pythonect ) após a análise, para cada iteração e o operador '->', o encadeamento é feito da seguinte maneira: thread = threading.Thread (target = __ run, args = ([( operador, item)] + expressão [1:], copy.copy (globals_), copy.copy (locals_), return_value_queue, não iterate_literal_arrays)) Thread.Start ()
Jonathan Rm

6

Python ( 101 93 98)

Esta é a solução de Peter Taylor. Funciona atrasando a impressão do N-ésimo caractere por N segundos. Ver comentários.

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

Este é o original:

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

Funcionou porque o tempo que leva para imprimir um único caractere é menor que o tempo que o Python leva para inicializar um novo encadeamento; portanto, o N-ésimo segmento terminaria antes que o N-1-ésimo segmento fosse criado. Aparentemente, é contra as regras confiar nisso.


Você pode salvar 3 caracteres alterando import sys,threadingpara import sys,threading as te você pode salvar mais 2, passando os argumentos para Thread como argumentos posicionais, em vez de argumentos de palavras-chave.
Joel Cornett

2
Onde está o código que trata da segurança de threads? Você apenas dispara threads esperando que eles funcionem na mesma ordem em que você os inicia. Isso nem sempre é verdade e é de fato a "parte mais difícil" desse problema. Em vez de otimizar o tamanho do programa, você deve considerar novamente o problema: você não o obteve em primeiro lugar. Consulte gist.github.com/2761278 para obter uma prova de que este código não funciona.
21412 silviot

Conserto rápido. Use em threading.Timervez de threading.Thread. Passe xcomo o parâmetro sleep.
Joel Cornett

1
A sugestão de Joel pode ser melhorada por 4 afor x in range(11):t.Timer(x,sys.stdout.write,"Hello World"[x]).start()
Peter Taylor

1
@ silviot: Eu estava explorando o fato de que a criação de threads envolve instanciar um objeto e, portanto, leva de um a dois terços de um milissegundo nos sistemas que testei. A saída de caracteres não possui essa sobrecarga, ocupando apenas um décimo desse tempo. Portanto, "sempre" funcionará, desde que você não substitua nada. O Stdout é armazenado em buffer, para que também nunca deva causar problemas.
Marinus

4

C # 73

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

não tenho certeza se isso satisfaz o requisito de que cada letra seja impressa por meio de sua própria linha, pois a tpl pode reutilizar as linhas.
Statichippo 20/05

Em teoria, você está certo, mas no meu pc, ThreadPool.GetMaxThreads ou ThreadPool.GetAvailableThreads retorna um valor em torno de 1000 para threads de E / S e de trabalho.
21412 JJos

4

APL (Dyalog Unicode) , SBCS de 28 bytes

Programa completo. Imprime em stderr. Inspirado pela solução de marinus .

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

Experimente online!

⍳11 primeiros 11 inteiros

'Hello World'{}&¨ Para cada número inteiro como argumento da direita ( ), gera a seguinte função com o caractere correspondente como argumento da esquerda ( ):

⎕DL⍵d e l ay segundos argumento direita

⍺⊣ descartar que (o atraso efetivo) em favor do caractere de argumento à esquerda

⍞← imprima isso no stdout sem quebras de linha à direita


que tal ⍞∘←&¨'dlroW olleH'? - Eu não sei se ele está garantida, teoricamente, mas parece sempre imprimi-los na ordem correta
NGN

@ngn Obviamente, como não há garantia de que os threads funcionem na ordem em que você os inicia, você deve tornar o thread do programa seguro para garantir que a saída seja impressa na ordem correta.
Adám 30/07/19

essa é a restrição que eu estava tentando resolver, pode ser garantido. Eu executei isso 100 vezes e parece que o agendador de threads sempre pega os threads na ordem inversa. Ou pelo menos é o caso quando há ≤11 tarefas. O AFAIK ⍞∘←não é interrompível (ou é? Talvez você possa perguntar a um desenvolvedor de C?). O Dyalog implementa threads verdes - 1 thread real que finge ser muitos; portanto, se uma opção de thread (verde) não puder ocorrer, a ordem é previsível.
ngn 30/07/19

3

Java (160 caracteres)

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

Sim, eu sei que esse é o idioma errado para o código de golfe, eu faço isso por diversão.


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 caracteres
Príncipe John Wesley

@ Prince Sim, obrigado pela correção!
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 caracteres
Wouter Coekaerts

@ Wouter Muito bom! Eu realmente senti falta disso.
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 caracteres
Prince John Wesley

2

Festança (64)

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

@marinus Golfed doen por 3 caracteres::()([ "$1" ]&&(printf "${1:0:1}"&: "${1:1}"));: Hello\ World
Digital Trauma

@fossilet Funciona para mim no Linux e no OSX, em várias versões do bash. Às vezes, os últimos um ou dois caracteres são impressos após o prompt do 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

Eu não tenho tanta certeza de multiplicar por 9999 - eu tenho um Xeon de 2Ghz no qual funcionará bem, mesmo que você não o faça, mas também tenho um Pentium 4 que precisa dele (999 deu saída ilegível e 99 não) não faça nada.)


Salve 2 caracteres usando em (*5^6)vez de (*9999)e não usando aspas para mapM_.
Caracol mecânico

@Mechanicalsnail Se você remover os backticks, precisará de um par extra de chaves, caso contrário ele será analisado como (((mapM_ (\(x,y) ... )) zip) [0..]) ...não desejado.
Marinus

Quanto a 999, pode estar sendo truncado para 0 devido a limitações do sistema operacional, mas posso estar errado. Qual sistema operacional você está usando?
Joey Adams

2

scala ( 81 79 caracteres)

def?(l:String){if(l.size!=0)new Thread{print(l(0));?(l.tail)}}
?("Hello World")

Um pouco mais curto: def? (L: String) {if (l.size> 0) new Thread {print (l (0));? (L.tail)}} #
Joa Ebert

@JoaEbert: sim, bom
Prince John Wesley

2

Groovy, 51 caracteres

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

1

D (135 caracteres)

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

Só inicio o próximo segmento quando já imprimi o caractere atual

editar +2 caracteres para uma melhor verificação vinculada


Eu recebo core.exception.RangeError@test.d(6): Range violationerro.
Fish Monitor

@fossilet Eu consertei
catraca anormal

1

Scala 74

"Hello World".zipWithIndex.par.map(x=>{Thread.sleep(x._2*99);print(x._1)})
  • zipWithIndex produz ((H, 0), (e, 1), (l, 2) ...).
  • par torna uma coleção paralela.

Testes:

(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- Eu entendi isso
Prince John Wesley

Também println(Thread.currentThread.getName)mostra que os threads não são exclusivos.
Prince John Wesley

@PrinceJohnWesley: Eu acho que você precisa de um núcleo por letra, para que o par distribua o trabalho por todos os núcleos.
usuário desconhecido

Deixa comigo. portanto, é necessário um núcleo por letra + alta resolução do relógio do sistema.
Prince John Wesley

use em mapvez de foreach. você pode salvar 4 caracteres.
Prince John Wesley

1

Javascript (72)

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

1

scala (45)

Solução baseada em junção do thread #

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

ou

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

1

Esta é minha tentativa de F #. Meu primeiro programa sério de F #. Por favor seja gentil.

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

0

Vai

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

Você não precisa contar os personagens - faremos isso por você!
usuário desconhecido

0

Erlang (90)

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

Compilar erlc +export_all h.erl



0

Python: muitos caracteres, mas funciona.

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

Não entendo qual é o objetivo de randomizar o tempo de sono.
Joel Cornett

@Joel para garantir que, quando funcione, não seja uma coincidência de sorte que os threads sejam executados na mesma ordem em que foram acionados.
silviot


0

Objective-C (183 caracteres)

-(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 Personagens

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

Como ele funciona é que cada thread começa no próximo depois de exibir seu caractere, de modo que coisas realmente úteis não podem acontecer fora de sequência.


0

Bash , 43 bytes

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

Experimente online!

xargsbifurca um printfprocesso separado para cada caractere (e aguarda sua saída).

Bash , 45 bytes, sem utilitários externos

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

Experimente online!

Expande para (printf H); (printf e); (printf l); (printf l); (printf o); (printf \ ); (printf W); (printf o); (printf r); (printf l); (printf d);antes da avaliação. Os parênteses tornam o Bash bifurcar um subshell para cada letra (e aguarde a saída), mas desta vez printfé o Bash embutido.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.