是的,这种跨语言的IPC完全是可能的。绝大多数文档、博客文章和回答(以及到目前为止在StackOverflow上的回答!)都假定与您所询问的相反,即Erlang / Elixir生成Python子进程,而不是Python生成Erlang / Elixir子进程。如果可以接受(即您的Erlang或Elixir应用程序启动Python进程),那太好了!Badu的答案将帮助您实现这一点,您还可以查看Elixir的Port模块的文档进行额外参考。
但这似乎不是你要找的答案,也不那么有趣。世界需要更多关于如何以Python脚本的子进程运行Erlang的文档!首先,我们的Python脚本(eip.py):
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
程序,它允许我们编写几乎是自包含的Erlang脚本,例如这里的
eip.escript
: "最初的回答"
#!/usr/bin/env escript
main(_Args) ->
Ping = io:get_line(""),
io:format("Pong: ~ts", [Ping]).
现在,当你运行
python3 eip.py
并在
Ping:
提示符处输入
asdf
时,你应该会得到
Pong: asdf
的返回结果。
使用Elixir做同样的事情只稍微复杂一些:我们需要创建一个Mix项目,并进行一些额外的配置,告诉Mix如何组合一个escript文件。因此,让我们从这个项目开始:
$ 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可能有点过头了,但我假设您最终想要做一些更高级的操作。
接下来,您需要在您的mix.exs
中添加一个escript
选项,像这样:
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
需要做一个小调整,指向这个新的Elixir化的ping/pong IPC东西:
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 处理方式导致它过早地认为已经到达文件结尾。但至少有一种方法是起作用的!" 最初的回答。
IO.gets
(或类似)读取,使用IO.puts
(或类似)写入,然后在Python中执行相反的操作(https://dev59.com/tWoy5IYBdhLWcg3wkOsK)。你试过了吗? - DogbertP1
也是一个Elixir进程呢? - stark