问题描述
我正在写论文申请。我需要线性编程,但是我的应用程序是用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 函数上达到了超时。
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。