通过 Erlport 执行的函数停止响应

Function executed via Erlport stops responding

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

长生不老药版本:1.10.4, 错误端口版本:0.10.1, Python版本:3.8.5, 纸浆版本:2.3

我已经为 Elixir-Python 通信编写了这样一个模块,它利用 GenServer 作为 Elixir 和 Python 之间的主要 'communication hub':

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]

而且效果很好。

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

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

鉴于 you can execute bash scripts using elixir, you can easily change the python script to be command line executable (I recommend 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.