假设我有一个简单的python脚本,它使用subprocess
模块执行elixir / erlang脚本。
假设python脚本的操作系统PID为P1
,并且运行的生成的elixir / erlang脚本的操作系统为P2
。
我想知道P1
和P2
之间的通信是否可行。更具体地说,P1
向stdin
的{{1}}写入内容,P2
从P2
读取收到的输入,并将一些相应的输出写入其自己的P1
stdout
1}}和P1
从stdout
的{{1}}读取并再次向P2
的{{1}}写入内容,依此类推。
我知道另一种方式是可能的,即从elixir / erlang内部生成外部进程,然后与进程通信。任何帮助表示感谢,谢谢。
答案 0 :(得分:2)
是的,这种跨语言IPC是完全可能的。绝大多数文档和博客文章等(以及到目前为止在StackOverflow上的答复!)都与您似乎要问的相反—即,他们假设Erlang / Elixir产生了Python子进程,而不是Python产生一个Erlang / Elixir子进程。如果还可以(例如,您对Erlang或Elixir应用程序可以简化Python进程,则可以),那就太好了! Badu的答案将帮助您做到这一点,并且您也可以在the documentation for Elixir's Port
module寻求帮助,以获取更多参考。
但是,这似乎并不是您要寻找的答案,这很不有趣。全世界需要更多有关如何进行相反操作的文档,所以让我们深入了解将Erlang作为Python脚本的子进程运行的美好世界!
首先,我们的Python脚本(eip.py
):
#!/usr/bin/env python
from subprocess import Popen, PIPE
erl = Popen(['escript', 'eip.escript'],
stdin=PIPE, stdout=PIPE, stderr=PIPE)
ping = input('Ping: ')
outs, errs = erl.communicate(input=ping.encode('utf-8'),
timeout=15)
print(outs.decode('utf-8'))
在Erlang方面(如您在该Python代码中可能已经注意到的那样),实现此目的的一种非常简单的方法是使用escript
程序,该程序允许我们编写或多或少的self包含的Erlang脚本,例如eip.escript
:
#!/usr/bin/env escript
main(_Args) ->
Ping = io:get_line(""),
io:format("Pong: ~ts", [Ping]).
现在,当您运行python3 eip.py
并在asdf
提示符下输入Ping:
时,应该返回Pong: asdf
。
用Elixir做相同的事情只是稍微复杂一点:我们需要创建一个带有一些额外配置的Mix项目,并告诉Mix将一个脚本文件放在一起。因此,让我们从项目开始:
$ mix new eip
* creating README.md
* creating .formatter.exs
* creating .gitignore
* creating mix.exs
* creating lib
* creating lib/eip.ex
* creating test
* creating test/test_helper.exs
* creating test/eip_test.exs
Your Mix project was created successfully.
You can use "mix" to compile it, test it, and more:
cd eip
mix test
Run "mix help" for more commands.
(对于这个简单的示例,甚至使用Mix可能也有些矫kill过正,但我假设您最终会想做比该示例更高级的操作)
接下来,您将要向escript
添加一个mix.exs
选项,如下所示:
defmodule Eip.MixProject do
use Mix.Project
def project, do: [
app: :eip,
version: "0.1.0",
elixir: "~> 1.9",
start_permanent: Mix.env() == :prod,
deps: deps(),
escript: escript()
]
def application, do: [extra_applications: [:logger]]
defp deps, do: []
defp escript, do: [main_module: Eip]
end
最后,您的lib/eip.ex
模块:
defmodule Eip do
def main(_argv) do
ping = IO.gets("")
IO.puts("Pong: #{ping}")
end
end
现在我们只需要构建它:
$ mix escript.build
Compiling 1 file (.ex)
Generated eip app
Generated escript eip with MIX_ENV=dev
eip.py
需要稍作调整,以指向此新的Elixirified ping / pong IPC whatamabob:
#!/usr/bin/env python
from subprocess import Popen, PIPE, TimeoutExpired
erl = Popen(['escript', 'eip/eip'],
stdin=PIPE, stdout=PIPE, stderr=PIPE)
ping = input('Ping: ')
outs, errs = erl.communicate(input=ping.encode('utf-8'))
print(outs.decode('utf-8'))
不幸的是,这完全无效:
$ python3 eip.py
Ping: asdf
Pong: eof
即使使用更直接的Erlang版本的端口(例如,将IO.gets("")
替换为:io.get_line("")
,将IO.puts("Pong: #{ping}")
替换为:io.fwrite("Pong: ~ts", [ping])
,也会发生相同的结果,这意味着特定于Elixir的STDIN处理通常使它过早地认为已到达文件结尾,但是,至少有一个方向可行!
答案 1 :(得分:0)