【问题标题】:Function executed via Erlport stops responding通过 Erlport 执行的函数停止响应
【发布时间】:2021-01-27 02:24:43
【问题描述】:

我正在写我的论文申请。我需要线性编程,但我的应用程序是用 Elixir 编写的,这真的不是这种操作的语言。这就是为什么我决定使用 Erlport 作为 Elixir 依赖项,它能够将 Python 代码与 Elixir 连接起来。我还使用 Pulp 作为优化的 Python 库。

Elixir 版本:1.10.4, Erlport 版本:0.10.1, Python版本:3.8.5, 纸浆版本:2.3

我为 Elixir-Python 通信编写了这样一个模块,它利用 GenServer 作为 Elixir 和 Python 之间的主要“通信中心”:

defmodule MyApp.PythonHub do
  use GenServer

  def start_link(_) do
    GenServer.start_link(__MODULE__, nil, name: __MODULE__)
  end

  def init(_opts) do
    path = [:code.priv_dir(:feed), "python"]
          |> Path.join() |> to_charlist()

    {:ok, pid} = :python.start([{ :python_path, path }, { :python, 'python3' }])

    {:ok, pid}
  end

  def handle_call({:call_function, module, function_name, arguments}, _sender, pid) do
    result = :python.call(pid, module, function_name, arguments)
    {:reply, result, pid}
  end

  def call_python_function(file_name, function_name, arguments) do
    GenServer.call(__MODULE__, {:call_function, file_name, function_name, arguments}, 10_000)
  end

end

GenServer 模块正在调用 python 文件,其中包含这样一个函数:

def calculate_meal_4(products_json, diet_json, lower_boundary, upper_boundary, enhance):
  from pulp import LpMinimize, LpProblem, LpStatus, lpSum, LpVariable, value
  import json
  products_dictionary = json.loads(products_json)
  print(products_dictionary)
  diets_dictionary = json.loads(diet_json)
  print(diets_dictionary)

  model = LpProblem(name="diet-minimization", sense=LpMinimize)

  # ... products setup ...

  x = LpVariable("prod_1_100g", lower_boundary, upper_boundary)
  y = LpVariable("prod_2_100g", lower_boundary, upper_boundary)
  z = LpVariable("prod_3_100g", lower_boundary, upper_boundary)
  w = LpVariable("prod_4_100g", lower_boundary, upper_boundary)

  optimization_function = # ... optimization function setup ...

  model += # ... optimization boundary function setup ...

  model += optimization_function

  print(model)

  solved_model = model.solve()

  print(value(model.objective))

  return [value(x), value(y), value(z), value(w)]

对 GenServer 本身的调用如下所示:

PythonHub.call_python_function(:diets, python_function, [products_json, meal_statistics_json, @min_portion, @max_portion, @macro_enhancement])

python_function:calculate_meal_4products_jsonmeal_statistic_json 是包含所需数据的 json。

在通过 python3 Diets.py 调用 calculate_meal_4 时,它会启动上面的 python 脚本并提供一些示例,但真实(取自应用程序),数据一切正常 -我几乎很快就得到了最小化的结果。通过 Elixir Erlport 调用 python 脚本时会出现问题。查看打印的输出,我可以看出它似乎一直有效,直到

solved_model = model.solve()

被调用。然后脚本似乎冻结了,GenServer 终于在 GenServer.call 函数上达到超时。

我还在一个简单的 python 测试文件上测试了调用:

def pass_var(a):
  print(a)
  return [a, a, a]

效果很好。

这就是为什么我现在真的很困惑,我正在寻找任何建议。可惜我什么也没找到。

【问题讨论】:

    标签: python elixir linear-programming pulp


    【解决方案1】:

    嗯,可能是调用外部求解器冻结了进程。

    鉴于you can execute bash scripts using elixir,您可以轻松地将python脚本更改为命令行可执行文件(我推荐click)。然后,您可以将输出写入 .json.csv 文件,并在完成后使用 Elixir 将其读回。

    @click.group()
    def cli():
        pass
    
    @cli.command()
    @click.argument('products_json', help='your array of products')
    @click.argument('diet_json', help='your dietary wishes')
    @click.option('--lower-bound', default=0, help='your minimum number of desired calories')
    @click.option('--upper-bound', default=100, help='your maximum number of desired calories')
    @click.option('--enhance', default=False, help="whether you'd like to experience our enhanced experience")
    def calculate_meal_4(products_json, diet_json, lower_boundary, upper_boundary, enhance):
        pass
    
    if __name__ == '__main__':
        cli()
    

    然后您可以使用 python3 my_file.py <products_json> <diet_json> ... 等调用它。

    你甚至可以validate the JSON and then return the parsed data directly

    【讨论】:

    • 嗨鲁本,谢谢你的回答。这对我来说似乎是一个可靠的解决方案。我已经设法为我的 python 脚本配置点击。从命令行执行它时效果很棒:python3 ~/Desktop/Thesis/FeedMe/feed/priv/python/calculate_diet_4.py <arg1> <arg2> ... 但是我在通过System.cmd/2 执行它时遇到问题 - 它返回我:enoent。 System.cmd("python3 ~/Desktop/Thesis/FeedMe/feed/priv/python/calculate_diet_4.py", ["#{products_json}", "#{meal_statistics_json}", "--lower_boundary=0.25", "--upper_boundary=3.5", "--enhance=10"])
    • 可能是不支持~ home 前缀。改用/usr/<yourname>/Desktop/Thesis/FeedMe/feed/priv/python/calculate_diet_4.py
    • 仍然是相同的结果,没有~ 前缀的文件的路径是:/Users/mac/Desktop/Thesis/FeedMe/feed/priv/python/calculate_diet_4.py - 从命令行执行时再次正常工作,但System.cmd/2:enoent 响应。
    • This answer 说您可能需要将文件名与其他参数放在一起。 System.cmd("python3", ["/Users/mac/Desktop/Thesis/FeedMe/feed/priv/python/calculate_diet_4.py", "#{products_json}", "#{meal_statistics_json}", "--lower_boundary=0.25", "--upper_boundary=3.5", "--enhance=10"])
    • 通过以下方式调用它:"cmd command" |> String.to_charlist() |> :os.cmd() 解决了它!谢谢你的帮助!将文件名与其他参数一起使用也可以:)
    猜你喜欢
    • 1970-01-01
    • 2014-04-18
    • 2021-11-26
    • 1970-01-01
    • 1970-01-01
    • 2012-01-08
    • 2017-09-01
    • 2021-06-11
    • 2017-09-05
    相关资源
    最近更新 更多