通过Erlport执行的功能停止响应

问题描述

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

Elixir版本:1.10.4, 出口版本:0.10.1, Python版本:3.8.5, PuLP版本: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,arguments)
    {:reply,result,pid}
  end

  def call_python_function(file_name,arguments) do
    GenServer.call(__MODULE__,{:call_function,file_name,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",upper_boundary)
  y = LpVariable("prod_2_100g",upper_boundary)
  z = LpVariable("prod_3_100g",upper_boundary)
  w = LpVariable("prod_4_100g",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_4 products_json meal_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,您可以轻松地将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