簡體   English   中英

Elixir / Erlang:與外部流程的溝通

[英]Elixir/Erlang: Communication with external process

假設我有一個簡單的python腳本,它使用subprocess模塊執行elixir / erlang腳本。

假設python腳本的OS PID是P1並且運行的生成的elixir / erlang腳本的OS是P2

我想知道P1P2之間的通信是否可行。 更具體地說, P1P2stdin寫入一些內容, P2P1讀取接收到的輸入,並將一些相應的輸出寫入其自己的stdoutP1P2stdout讀取,並再次向P2stdin寫入內容,依此類推。

我知道另一種方式是可能的,即從elixir / erlang內部生成外部進程,然后與進程通信。 任何幫助表示感謝,謝謝。

是的,這種跨語言的IPC是完全可能的。 絕大多數文檔和博客文章等(以及到目前為止在StackOverflow上的響應!)假設與您似乎要求的相反 - 也就是說,他們假設Erlang / Elixir正在生成Python子流程,而不是Python產生Erlang / Elixir子進程。 如果這沒關系(即你的Erlang或Elixir應用程序可以啟動Python過程),那就太好了! Badu的答案將幫助您做到這一點,您也可以在Elixir的Port模塊的文檔中獲得額外的參考。

但這似乎不是你尋求的答案,而且那不那么有趣。 世界需要更多關於如何反過來的文檔,所以讓我們深入探討運行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程序,它允許我們編寫或多或少的自包含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可能有點過頭了,但我假設你最終想要做比這個例子更高級的事情)

接下來,你要添加一個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 thingamabob:

#!/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處理通常會導致它過早地認為它已達到文件末尾。但是,至少有一個方向可行!

就像Dogbert說的那樣,你可以使用Ports代替。 查看Erlport是一篇關於Elixir和Python之間通信的博客文章

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM