HelolW rdlo (un desafío de subprocesos)


39

Tengo un reto para usted:

  • Imprime "Hello World" en cualquier idioma.
  • Cada personaje debe imprimirse desde su propio hilo único.

Eso es. Obviamente, como no hay garantía de que los subprocesos funcionen en el orden en que los inicia, debe hacer que el subproceso de su programa sea seguro para garantizar que la salida se imprima en el orden correcto.

Y, como se trata de código de golf, gana el programa más corto.

Actualizar:

El ganador es la entrada APL de Marinus , con 34 caracteres. También gana el premio por la entrada menos legible.


10
Un mejor nombre para esto habría sidoHelolW rdlo
Cristian Lupascu

Ja, eso me gusta.
Cambiarlo de

Aww ... es demasiado corto
Tharwen

1
Es divertido ver cuántas personas ignoran la pista "obviamente, ya que no hay garantía de que los hilos operen en el orden en que los inicias" y piensan que lo hicieron bien.
Joa Ebert

Si bien es cierto que "no hay garantía de que los hilos operen en el orden en que los inicias" en la práctica, casi siempre lo harán para un programa tan trivial. Para evitar esta confusión, agregaría al problema que cada subproceso debe 1) esperar un número aleatorio (pequeño) de milisegundos 2) emitir su char 3) esperar otro tiempo aleatorio (tal vez largo) De esta manera la gente podría decir si el código funciona simplemente ejecutándolo un par de veces. Y las soluciones join () funcionarían mucho peor. Sin una espera aleatoria, una carrera exitosa podría inducir a error al pensar que su programa es correcto.
silviot

Respuestas:


10

APL (Dyalog) ( 44 43 39 34)

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

Explicación:

  • 2 11⍴'Hello World',⍳11 crea una matriz: (H, 1), (e, 2), ...
  • &⌿ significa: para cada columna de la matriz, hacer en un hilo separado:
  • En un hilo, ahora es el personaje y ahora es el momento
  • ⎕DL⊃⍵espera por segundos
  • Luego, ⍞←⍺genera el carácter.

11
¿Sabes que? Tomaré tu palabra por ello ... :)
Refuerce

OK, este es el más corto. ¡Felicidades!
Tharwen

19

C, 61 62 caracteres

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

Todas las funciones de la biblioteca pthread tienen muuuucho nombres, así que en su lugar, inicié un proceso completamente separado para cada personaje. fork()Es mucho más corto.

Era necesario usarlo en write()lugar de putchar()porque las funciones de almacenamiento en búfer stdio no son seguras para subprocesos.

Editado : Copia de seguridad de hasta 62 caracteres. En mi celo, bajar a 61 caracteres también dejó caer el hilo de seguridad.


Debería ser posible cambiar la instrucción de escritura write(1,"Hello World\n",!!++i)por 2 bytes. Buena solución de lo contrario.
primo

Deberías probar eso y ver qué produce.
breadbox

Mi error, quise decir!!++i
primo

Parece ser lo que escribiste la primera vez, así que no veo qué error estabas tratando de corregir. Y no estaba siendo gracioso: honestamente quería decir que deberías probarlo tú mismo y ver qué pasa. Al eliminar la adición, cada hilo imprimirá el primer carácter de la cadena.
breadbox

Originalmente había escrito !!i++, pero lo edité unos segundos después, porque me di cuenta de que se evaluaría 0en la primera iteración. Asumí que habías visto la versión sin editar. No puedo probar su código, porque solo imprime el primer carácter, una vez . Sin embargo, hay muchas alternativas; i++<13, usando !!i, o inclusowrite(1,"Hello World\n",i++>13||fork()||main())
primo

9

Ruby, 46 caracteres.

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

Se sincroniza debido al hecho de que el programa espera a que finalice el subproceso antes de comenzar el siguiente subproceso y continuar con el siguiente carácter.


7

Pythonect (35 caracteres)

http://www.pythonect.org

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

Este es el más corto hasta ahora. Como no tengo idea de lo que realmente hace, supondré que es correcto y lo aceptaré en un día o dos si nadie habla en contra o publica algo más corto.
Tharwen

1
Acabo de echar un vistazo a los ejemplos. ¿No debería la declaración de impresión o la declaración de lista tener corchetes [] alrededor?
Dalin Seivewright

1
Hola, estoy reenviando la respuesta de Itzik (creador de pythonect): '->' y '|' son ambos operadores Pythonect. El operador de tubería pasa un elemento a un elemento, mientras que el otro operador pasa todos los elementos a la vez. Lo que hace el programa anterior es, toma la cadena "Hello World", la convierte en una lista, divide la lista en caracteres y envía cada carácter para imprimir. Es posible optimizar el programa aún más, a lo siguiente: iter ("Hello World") | print Lo que hace es, itera la cadena "Hello World" y envía cada carácter a imprimir (de manera sincronizada / bloqueante). Saludos, Itzik Kotler | ikotler.org
Leon Fedotov

¿Cómo se hace el enhebrado aquí?
Rohit

1
Como mencionó @LeonFedotov, y desde la fuente pythonect (disponible en pythonect ) después del análisis, para cada iteración y el operador '->', el enhebrado se realiza así: thread = threading.Thread (target = __ run, args = ([((( operador, elemento)] + expresión [1:], copy.copy (globals_), copy.copy (locals_), return_value_queue, not iterate_literal_arrays)) thread.start ()
Jonathan Rom

6

Python ( 101 93 98)

Esta es la solución de Peter Taylor. Funciona retrasando la impresión del enésimo carácter en N segundos. Ver comentarios.

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

Este es el original:

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

Funcionó porque el tiempo que lleva imprimir un solo carácter es menor que el tiempo que tarda Python en inicializar un nuevo subproceso, por lo tanto, el subproceso N terminaría antes de que se creara el subproceso N + 1. Aparentemente es contrario a las reglas confiar en esto.


Puede guardar 3 caracteres cambiando import sys,threadinga import sys,threading as ty puede guardar 2 más, pasando los argumentos a Thread como argumentos posicionales, en lugar de argumentos de palabras clave.
Joel Cornett

2
¿Dónde está el código que se ocupa de la seguridad del hilo? Simplemente disparas hilos esperando que se ejecuten en el mismo orden en que los inicias. Esto no siempre será cierto y de hecho es la "parte difícil" de este problema. En lugar de optimizar el tamaño de su programa, debería volver a considerar el problema: no lo obtuvo en primer lugar. Consulte gist.github.com/2761278 para obtener una prueba de que este código no funciona.
silviot

Arreglo rapido. Usar en threading.Timerlugar de threading.Thread. Pase xcomo el parámetro de suspensión.
Joel Cornett

1
La sugerencia de Joel se puede mejorar en 4 afor x in range(11):t.Timer(x,sys.stdout.write,"Hello World"[x]).start()
Peter Taylor

1
@silviot: estaba explotando el hecho de que la creación de subprocesos implica la creación de instancias de un objeto y, por lo tanto, toma de uno a dos tercios de un milisegundo en los sistemas que he probado. La salida de caracteres no tiene esta sobrecarga, tomando solo una décima parte de este tiempo. Por lo tanto, "siempre" funcionará, siempre y cuando no anule nada. Stdout está protegido, por lo que tampoco debería dar problemas.
Marinus

4

C # 73

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

No estoy seguro de que esto satisfaga el requisito de que cada letra se imprima a través de su propio hilo, ya que el tpl puede reutilizar hilos.
statichippo

En teoría tiene razón, pero en mi PC ThreadPool.GetMaxThreads o ThreadPool.GetAvailableThreads devuelve un valor de alrededor de 1000 para los hilos de trabajo y de E / S.
JJoos

4

APL (Dyalog Unicode) , SBCS de 28 bytes

Programa completo Imprime en stderr. Inspirado en la solución de marinus .

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

Pruébalo en línea!

⍳11 primeros 11 enteros

'Hello World'{}&¨ Para cada entero como argumento derecho ( ), genera la siguiente función con el carácter correspondiente como argumento izquierdo ( ):

⎕DL⍵d e l segundos de argumento correcto

⍺⊣ descartar eso (la demora efectiva) a favor del carácter de argumento izquierdo

⍞← imprima eso en stdout sin salto de línea final


¿qué tal ⍞∘←&¨'dlroW olleH'? - No sé si se garantiza en teoría, pero parece que siempre se imprima en el orden correcto
NGN

@ngn Obviamente, como no hay garantía de que los subprocesos funcionarán en el orden en que los inicia, debe hacer que el subproceso de su programa sea seguro para garantizar que la salida se imprima en el orden correcto.
Adám

esa es la restricción que estaba tratando de abordar, podría estar garantizado. Ejecuté esto 100 veces y parece que el programador de subprocesos siempre recoge los subprocesos en orden inverso. O al menos ese es el caso cuando hay ≤11 tareas. AFAIK ⍞∘←no es interrumpible (¿o sí? ¿Tal vez puedas preguntarle a un desarrollador C?). Dyalog implementa hilos verdes: 1 hilo real que finge ser muchos, por lo que si no se puede producir un cambio de hilo (verde), el orden es predecible.
ngn

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

Sí, sé que este es el lenguaje incorrecto para el golf de código, lo hago por diversión.


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 Sí, gracias por la corrección!
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 ¡Muy buena! Lo extrañé totalmente.
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
Príncipe John Wesley

2

Golpe (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 mí en Linux y OSX, varias versiones de bash. El último uno o dos caracteres a veces se imprime después de la solicitud del shell.
Trauma digital

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

No estoy tan seguro de multiplicar por 9999: tengo un Xeon de 2Ghz en el que funcionará bien incluso si no lo haces, pero también tengo un Pentium 4 que lo necesita (999 dio una salida confusa y 99 no No hagas nada en absoluto.)


Guarde 2 caracteres usando en (*5^6)lugar de (*9999)y sin usar comillas inversas para mapM_.
Caracol mecánico

@Mechanicalsnail Si elimina los backticks, necesita un par adicional de llaves, de lo contrario, se analiza como (((mapM_ (\(x,y) ... )) zip) [0..]) ...lo que no desea.
Marinus

En cuanto a 999, podría truncarse a 0 debido a limitaciones del sistema operativo, pero podría estar equivocado. ¿Qué sistema operativo estás usando?
Joey Adams



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

Solo comienzo el siguiente hilo cuando ya he impreso el carácter actual

editar +2 caracteres para una mejor verificación encuadernada


Me sale un core.exception.RangeError@test.d(6): Range violationerror
Fish Monitor

@fossilet lo arreglé
monstruo de trinquete

1

Scala 74

"Hello World".zipWithIndex.par.map(x=>{Thread.sleep(x._2*99);print(x._1)})
  • zipWithIndex produce ((H, 0), (e, 1), (l, 2) ...).
  • par lo convierte en una colección paralela.

Pruebas:

(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- Tengo esto
Príncipe John Wesley

También println(Thread.currentThread.getName)muestra que los hilos no son únicos.
Príncipe John Wesley

@PrinceJohnWesley: Supongo que necesitas un núcleo por letra, por lo que el par distribuirá el trabajo en todos los núcleos.
usuario desconocido

Entiendo. entonces se requiere un núcleo por letra + alta resolución del reloj del sistema.
Príncipe John Wesley

usar en maplugar de foreach. Puedes guardar 4 caracteres.
Príncipe John Wesley

1

Javascript (72)

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

1

Scala (45)

Hilo # unirse a la solución basada

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

o

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

1

Este es mi intento de F #. Mi primer programa serio de F #. Por favor se amable.

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

0

Ir

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

No necesita contar los personajes, ¡lo haremos por usted!
usuario desconocido

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: demasiados caracteres, pero 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()

No entiendo cuál es el propósito de aleatorizar el tiempo de sueño.
Joel Cornett

@Joel para asegurarse de que, cuando funciona, no es una coincidencia afortunada que los hilos se ejecuten en el mismo orden en que fueron disparados.
silviot


0

Objetivo-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 Personajes

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

La forma en que funciona es que cada subproceso comienza el siguiente después de haber mostrado su carácter, por lo que las cosas realmente útiles no pueden suceder fuera de secuencia.


0

Bash , 43 bytes

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

Pruébalo en línea!

xargs se bifurca por separado printf proceso para cada personaje (y espera a que salga).

Bash , 45 bytes, sin utilidades externas

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

Pruébalo en línea!

Se expande a (printf H); (printf e); (printf l); (printf l); (printf o); (printf \ ); (printf W); (printf o); (printf r); (printf l); (printf d);antes de la evaluación. Los paréntesis hacen que Bash se bifurque en un subshell para cada letra (y espere a que salga), pero esta vez printfes el Bash incorporado.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.