特别声明:未经允许,请勿转载!
https://discourse.juliacn.com/t/topic/7189https://discourse.juliacn.com/t/topic/7189我在julia中国社区已提交了文章的最后部分未解决问题,大家后续可以在该链接中跟踪问题的回答进度。
好几年前就接触过julia,当时觉得并不好用,
如今julia版本已经来到了1.8.5版本,但是仍觉得它的生态还是不够好,很多问题都找不到答案。
我记录下当前的使用情况,在C#调用julia这块,结合前人的使用示例,我认为我这篇文章应该属于C#操作julia是最全的了。
在C#调用julia方面,目前已实现了如何使用以下函数(还有很多API接口函数可以在julia.h和jlapi.c中找到,但是要全部都会使用又是另一回事了):
jl_call1
jl_call2
jl_call3
jl_init__threading
jl_eval_string
jl_unbox_float64
jl_box_float64
jl_atexit_hook
此前搜索到前辈们留下的一个问题,
http://cn.voidcc.com/question/p-dhvlazdi-ux.htmlhttp://cn.voidcc.com/question/p-dhvlazdi-ux.html该链接是前人未结案的文章,至少我是这么认为。
我发现他的第1个和第2个结果是错误的,我把
public static extern IntPtr jl_box_float64(float value);
改为(float => double)
public static extern IntPtr jl_box_float64(double value);
得到的结果就正常了。
但是以下遇到的问题仍未解决.
julia脚本如下:
module JuliaClass
export calculate
function calculate(a::Float64, b::Float64)::Float64
return a * pi + b^2
end
function calcMore(a, b)
return ones(a, b)::Array{Float64,2};
end
function calc3par(a, b, c)
return (a + b + c)::Float64;
end
function calcArray(a::Array{Float64,1})
return (a[0] + a[1] + a[2])::Float64;
end
end
C#脚本如下:
//====================================================================
[DllImport("kernel32.dll")]
static extern bool SetDllDirectory(string lpPathName);
[DllImport("libjulia.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern void jl_init__threading(string path);
[DllImport("libjulia.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr jl_eval_string(string input);
[DllImport("libjulia.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr jl_box_float64(double value);
[DllImport("libjulia.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern double jl_unbox_float64(IntPtr value);
[DllImport("libjulia.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr jl_get_global(IntPtr func, string name);
[DllImport("libjulia.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr jl_call(IntPtr func, IntPtr[] v1, int v2);
[DllImport("libjulia.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr jl_call1(IntPtr func, IntPtr v1);
[DllImport("libjulia.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr jl_call2(IntPtr func, IntPtr v1, IntPtr v2);
[DllImport("libjulia.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr jl_call3(IntPtr func, IntPtr v1, IntPtr v2, IntPtr v3);
[DllImport("libjulia.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern void jl_atexit_hook(int a);
//====================================================================
private void button_CsCallJulia_Click(object sender, EventArgs e)
{
///加载julia环境路径
string julia_home_dir = Application.StartupPath + "\\Julia-1.8.5\\bin";//我的WinForm是32位的,所以安装的是32位的julia
SetDllDirectory(julia_home_dir);
jl_init__threading(julia_home_dir);
///加载julia脚本路径
string jl_ScriptPath = "./JuliaScript/test_julia.jl";
string jl_include = "include(\"" + jl_ScriptPath + "\")";
///等效于julia>include("./JuliaScript/test_julia.jl")
IntPtr jl_DoString = jl_eval_string(jl_include);
///执行julia脚本中JuliaClass模块的calculate函数
IntPtr jl_ret = jl_eval_string("JuliaClass.calculate(2.0,4.0)");///julia函数返回值给C#中的IntPtr类型
double cs_val = jl_unbox_float64(jl_ret);///julia拆箱转换为C#的double数据类型
Console.WriteLine("result1={0}", cs_val);
///C#传递参数给julia
IntPtr jl_function = jl_eval_string("JuliaClass.calculate");
IntPtr jl_par1 = jl_box_float64(3.0);///C#参数1装箱
IntPtr jl_par2 = jl_box_float64(4.0);///C#参数2装箱
jl_ret = jl_call2(jl_function, jl_par1, jl_par2);///传入到julia指定模块中的函数,以及参数,注:jl_call2只能传递1个函数和2个参数
cs_val = jl_unbox_float64(jl_ret);///julia拆箱转换为C#的double数据类型
Console.WriteLine("result2={0}", cs_val);
jl_function = jl_eval_string("JuliaClass.calc3par");
jl_par1 = jl_box_float64(12.0);
jl_par2 = jl_box_float64(13.0);
IntPtr jl_par3 = jl_box_float64(14.0);
jl_ret = jl_call3(jl_function, jl_par1, jl_par2, jl_par3);
cs_val = jl_unbox_float64(jl_ret);
Console.WriteLine("result3={0}", cs_val);
}
问题就是:
1.我不知道如何在C#里通过jl_call传递一个数组到julia中的calcArray函数,
我尝试->
jl_function = jl_eval_string("JuliaClass.calcMore");
IntPtr[] jl_par = new IntPtr[3] { (IntPtr)11, (IntPtr)12, (IntPtr)13 };
jl_ret = jl_call(jl_function, jl_par, 3);
Console.WriteLine("result4={0}", jl_ret);
运行这段代码它报错如下:
result1=22.2831853071796
result2=25.4247779607694
result3=39
引发的异常:“System.AccessViolationException”(位于 RobotTestingAPP.exe 中)
“System.AccessViolationException”类型的未经处理的异常在 RobotTestingAPP.exe 中发生
尝试读取或写入受保护的内存。这通常指示其他内存已损坏。
因此我不知道在C#中如何正确使用jl_call,搜索全网找不到答案!
2.如何在C#中使用jl_base_module等函数,如果是用C++调用,则是很方便,但我对C++并不了解。