J'essaie d'apprendre à faire l'interopérabilité d'Elixir avec le module de porcelaine.
Alors j'ai fait cet exemple simple:
J'ai une fonction Elixir qui ressemble à ceci:
defmodule PythonMessenger do
alias Porcelain.Process, as: Proc
alias Porcelain.Result
def test_messages do
proc = %Proc{pid: pid} =
Porcelain.spawn_shell("python ./python_scripts/reply_to_elixir.py",
in: :receive, out: {:send, self()})
Proc.send_input(proc, "Greetings from Elixirn")
data = receive do
{^pid, :data, :out, data} -> data
end
IO.inspect data
Proc.send_input(proc, "Elixir: I heard you said "#{data}"n")
data = receive do
{^pid, :data, data} -> data
end
IO.inspect data
Proc.send_input(proc, "Please quitn")
data = receive do
{^pid, :data, data} -> data
end
IO.inspect data
end
end
et un script python qui ressemble à ceci:
import sys
while 1:
line = sys.stdin.readline()
if "quit" in line:
print("Quitting, bye for now")
sys.exit()
print(line)
mais ça ne marche pas. Le script python ne se ferme jamais. Si un lu seulement une ligne comme:
line = sys.stdin.readline()
cela fonctionne très bien.
Alors quel est le problème, des idées?
Réponses:
3 pour la réponse № 1Vous devez passer -u
désactiver la mise en mémoire tampon sys.stdin.readline()
. Vous ne verrez pas cela lors de l'exécution du programmede manière interactive, mais vous le verrez lorsque le programme est créé sans TTY. En raison de la mise en mémoire tampon par défaut, le processus Python n’imprimait rien pour un message court tel que "Greetings from Elixirn"
et à cause de la receive
expression, le code Elixir bloquait pour toujours, attendant que le processus Python imprime quelque chose.
De man python
:
-u Force stdin, stdout and stderr to be totally unbuffered. On systems where it matters, also
put stdin, stdout and stderr in binary mode. Note that there is internal buffering in xread-
lines(), readlines() and file-object iterators ("for line in sys.stdin") which is not influ-
enced by this option. To work around this, you will want to use "sys.stdin.readline()" inside
a "while 1:" loop.
Vous avez également eu des erreurs en 2ème et 3ème receive
modèles. Voici le code qui fonctionne pour moi:
defmodule PythonMessenger do
alias Porcelain.Process, as: Proc
alias Porcelain.Result
def test_messages do
proc = %Proc{pid: pid} =
Porcelain.spawn_shell("python -u ./a.py",
in: :receive, out: {:send, self()})
Proc.send_input(proc, "Greetings from Elixirn")
data = receive do
{^pid, :data, :out, data} -> data
end
IO.inspect data
Proc.send_input(proc, "Elixir: I heard you said "#{data}"n")
data = receive do
{^pid, :data, :out, data} -> data
end
IO.inspect data
Proc.send_input(proc, "Please quitn")
data = receive do
{^pid, :data, :out, data} -> data
end
IO.inspect data
end
end
PythonMessenger.test_messages
Sortie:
"Greetings from Elixirnn"
"Elixir: I heard you said "Greetings from Elixirnnnn"
""nn"