En Python sin pila, ¿puedes enviar un canal a través de un canal?
-
10-07-2019 - |
Pregunta
No tengo sin pila ejecutándose actualmente, así que no puedo probarlo yo mismo.
import stackless
ch1 = stackless.channel()
ch2 = stackless.channel()
ch1.send(ch2)
ch3 = ch1.receive()
¿Son ch2 y ch3 el mismo canal? Diga:
text = "Hallo"
ch2.send(text)
assert text == ch3.receive()
Esta función me recordó una habla sobre Newsqueak que Robert Pike (de < a href = "http://en.wikipedia.org/wiki/Plan_9_from_Bell_Labs" rel = "nofollow noreferrer"> Plan9 fama) dio en Google. En Newsqueak puede enviar canales a través de canales.
Solución
Sí Acabo de probar.
>>> import stackless
>>> ch1 = stackless.channel()
>>> def a():
... ch2 = stackless.channel()
... ch1.send(ch2)
... ch2.send("Hello")
...
>>> def b():
... ch3 = ch1.receive()
... print ch3.receive()
...
>>> stackless.tasklet(a)()
<stackless.tasklet object at 0x01C6FCB0>
>>> stackless.tasklet(b)()
<stackless.tasklet object at 0x01C6FAB0>
>>> stackless.run()
Hello
Otros consejos
Los canales envían referencias normales de Python, por lo que los datos que envía (canal, cadena, lo que sea) es exactamente lo que se recibe.
Un ejemplo de envío de un canal a través de un canal es cuando utiliza un tasklet como servicio, es decir, un tasklet escucha solicitudes en un canal, funciona y devuelve el resultado. La solicitud debe incluir los datos para el trabajo y el canal de retorno para el resultado, de modo que el resultado llegue al solicitante.
Aquí hay un ejemplo extremo que desarrollé para mi Charla sin pila en PyCon hace unos años. Esto crea un nuevo tasklet para cada llamada de función, por lo que puedo usar una implementación recursiva de factorial que no necesita preocuparse por el límite de pila de Python. Asigno un tasklet para cada llamada y obtiene el canal de retorno para el resultado.
import stackless
def call_wrapper(f, args, kwargs, result_ch):
result_ch.send(f(*args, **kwargs))
# ... should also catch and forward exceptions ...
def call(f, *args, **kwargs):
result_ch = stackless.channel()
stackless.tasklet(call_wrapper)(f, args, kwargs, result_ch)
return result_ch.receive()
def factorial(n):
if n <= 1:
return 1
return n * call(factorial, n-1)
print "5! =", factorial(5)
print "1000! / 998! =", factorial(1000)/factorial(998)
El resultado es:
5! = 120
1000! / 998! = 999000
Tengo algunos otros ejemplos de envío de canales a través de canales en mi presentación. Es algo común en Stackless.